On Sat, Apr 25, 2009 at 6:42 AM, Grzegorz Jaskiewicz <g...@pointblue.com.pl> wrote: > On 25 Apr 2009, at 04:52, Robert Haas wrote: >> blow the hash-join plan out of the water anyway... but Stephen Frost >> was telling me at JDcon East that he sometimes sets it to something >> like 8GB when he's the only user on his apparently-quite-awesome >> hardware...) > > For the record, because most queries have 5-6 joins here, I always set it up > to 32MB on production. We don't have more than 100-150 connections, so it > plays well on normal 32bit machine with 4GB. > > If what you wrote about hash-join is confirmed by others, than I am pretty > much +100 for fixing it. > > (just my penny).
You may find the attached patch interesting to play around with. It changes the NTUP_PER_BUCKET into a GUC called hash_load, and adds EXPLAIN support to show the number of buckets and batches. This is just for experimentation: I'm not in favor of adding Yet Another Thing for users to tune, but if you try it out, you will see (I think) that changing hash_load has a dramatic effect on the estimated cost of a hash join but a much less dramatic effect on the actual run-time. ...Robert
*** a/src/backend/commands/explain.c --- b/src/backend/commands/explain.c *************** *** 786,791 **** explain_outNode(StringInfo str, --- 786,794 ---- quote_identifier(rte->eref->aliasname)); } break; + case T_Hash: + appendStringInfo(str, " buckets=%d batches=%d", + ((Hash *) plan)->num_buckets, ((Hash *) plan)->num_batches); default: break; } *** a/src/backend/executor/nodeHash.c --- b/src/backend/executor/nodeHash.c *************** *** 48,53 **** static void ExecHashSkewTableInsert(HashJoinTable hashtable, --- 48,55 ---- int bucketNumber); static void ExecHashRemoveNextSkewBucket(HashJoinTable hashtable); + int hash_load; + /* ---------------------------------------------------------------- * ExecHash *************** *** 391,399 **** ExecHashTableCreate(Hash *node, List *hashOperators) * This is exported so that the planner's costsize.c can use it. */ - /* Target bucket loading (tuples per bucket) */ - #define NTUP_PER_BUCKET 10 - void ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, int *numbuckets, --- 393,398 ---- *************** *** 463,469 **** ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, *num_skew_mcvs = 0; /* ! * Set nbuckets to achieve an average bucket load of NTUP_PER_BUCKET when * memory is filled. Set nbatch to the smallest power of 2 that appears * sufficient. */ --- 462,468 ---- *num_skew_mcvs = 0; /* ! * Set nbuckets to achieve an average bucket load of hash_load when * memory is filled. Set nbatch to the smallest power of 2 that appears * sufficient. */ *************** *** 474,480 **** ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, double dbatch; int minbatch; ! lbuckets = (hash_table_bytes / tupsize) / NTUP_PER_BUCKET; lbuckets = Min(lbuckets, INT_MAX / 2); nbuckets = (int) lbuckets; --- 473,479 ---- double dbatch; int minbatch; ! lbuckets = (hash_table_bytes / tupsize) / hash_load; lbuckets = Min(lbuckets, INT_MAX / 2); nbuckets = (int) lbuckets; *************** *** 490,496 **** ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, /* We expect the hashtable to fit in memory */ double dbuckets; ! dbuckets = ceil(ntuples / NTUP_PER_BUCKET); dbuckets = Min(dbuckets, INT_MAX / 2); nbuckets = (int) dbuckets; --- 489,495 ---- /* We expect the hashtable to fit in memory */ double dbuckets; ! dbuckets = ceil(ntuples / hash_load); dbuckets = Min(dbuckets, INT_MAX / 2); nbuckets = (int) dbuckets; *** a/src/backend/optimizer/path/costsize.c --- b/src/backend/optimizer/path/costsize.c *************** *** 1880,1887 **** cost_hashjoin(HashPath *path, PlannerInfo *root, SpecialJoinInfo *sjinfo) &numbatches, &num_skew_mcvs); virtualbuckets = (double) numbuckets *(double) numbatches; ! /* mark the path with estimated # of batches */ path->num_batches = numbatches; /* * Determine bucketsize fraction for inner relation. We use the smallest --- 1880,1888 ---- &numbatches, &num_skew_mcvs); virtualbuckets = (double) numbuckets *(double) numbatches; ! /* mark the path with estimated # of batches & buckets */ path->num_batches = numbatches; + path->num_buckets = numbuckets; /* * Determine bucketsize fraction for inner relation. We use the smallest *** a/src/backend/optimizer/plan/createplan.c --- b/src/backend/optimizer/plan/createplan.c *************** *** 116,122 **** static Hash *make_hash(Plan *lefttree, Oid skewTable, AttrNumber skewColumn, Oid skewColType, ! int32 skewColTypmod); static MergeJoin *make_mergejoin(List *tlist, List *joinclauses, List *otherclauses, List *mergeclauses, --- 116,124 ---- Oid skewTable, AttrNumber skewColumn, Oid skewColType, ! int32 skewColTypmod, ! int num_buckets, ! int num_batches); static MergeJoin *make_mergejoin(List *tlist, List *joinclauses, List *otherclauses, List *mergeclauses, *************** *** 1954,1960 **** create_hashjoin_plan(PlannerInfo *root, skewTable, skewColumn, skewColType, ! skewColTypmod); join_plan = make_hashjoin(tlist, joinclauses, otherclauses, --- 1956,1964 ---- skewTable, skewColumn, skewColType, ! skewColTypmod, ! best_path->num_buckets, ! best_path->num_batches); join_plan = make_hashjoin(tlist, joinclauses, otherclauses, *************** *** 2766,2772 **** make_hash(Plan *lefttree, Oid skewTable, AttrNumber skewColumn, Oid skewColType, ! int32 skewColTypmod) { Hash *node = makeNode(Hash); Plan *plan = &node->plan; --- 2770,2778 ---- Oid skewTable, AttrNumber skewColumn, Oid skewColType, ! int32 skewColTypmod, ! int num_buckets, ! int num_batches) { Hash *node = makeNode(Hash); Plan *plan = &node->plan; *************** *** 2787,2792 **** make_hash(Plan *lefttree, --- 2793,2800 ---- node->skewColumn = skewColumn; node->skewColType = skewColType; node->skewColTypmod = skewColTypmod; + node->num_buckets = num_buckets; + node->num_batches = num_batches; return node; } *** a/src/backend/optimizer/util/pathnode.c --- b/src/backend/optimizer/util/pathnode.c *************** *** 1493,1499 **** create_hashjoin_path(PlannerInfo *root, */ pathnode->jpath.path.pathkeys = NIL; pathnode->path_hashclauses = hashclauses; ! /* cost_hashjoin will fill in pathnode->num_batches */ cost_hashjoin(pathnode, root, sjinfo); --- 1493,1500 ---- */ pathnode->jpath.path.pathkeys = NIL; pathnode->path_hashclauses = hashclauses; ! /* cost_hashjoin will fill in pathnode->num_batches ! * and pathnode->num_buckets */ cost_hashjoin(pathnode, root, sjinfo); *** a/src/backend/utils/misc/guc.c --- b/src/backend/utils/misc/guc.c *************** *** 36,41 **** --- 36,42 ---- #include "commands/vacuum.h" #include "commands/variable.h" #include "commands/trigger.h" + #include "executor/nodeHash.h" #include "funcapi.h" #include "libpq/auth.h" #include "libpq/pqformat.h" *************** *** 1281,1286 **** static struct config_int ConfigureNamesInt[] = --- 1282,1296 ---- 8, 1, INT_MAX, NULL, NULL }, { + {"hash_load", PGC_USERSET, QUERY_TUNING_OTHER, + gettext_noop("Sets the target load factor for " + "hash tables constructed by a Hash executor node."), + NULL + }, + &hash_load, + 10, 1, INT_MAX, NULL, NULL + }, + { {"geqo_threshold", PGC_USERSET, QUERY_TUNING_GEQO, gettext_noop("Sets the threshold of FROM items beyond which GEQO is used."), NULL *** a/src/backend/utils/misc/postgresql.conf.sample --- b/src/backend/utils/misc/postgresql.conf.sample *************** *** 222,227 **** --- 222,228 ---- #from_collapse_limit = 8 #join_collapse_limit = 8 # 1 disables collapsing of explicit # JOIN clauses + #hash_load = 10 # target # of tuples per hash bucket #------------------------------------------------------------------------------ *** a/src/include/executor/nodeHash.h --- b/src/include/executor/nodeHash.h *************** *** 47,50 **** extern void ExecChooseHashTableSize(double ntuples, int tupwidth, bool useskew, --- 47,52 ---- int *num_skew_mcvs); extern int ExecHashGetSkewBucket(HashJoinTable hashtable, uint32 hashvalue); + extern int hash_load; + #endif /* NODEHASH_H */ *** a/src/include/nodes/plannodes.h --- b/src/include/nodes/plannodes.h *************** *** 581,586 **** typedef struct Hash --- 581,588 ---- AttrNumber skewColumn; /* outer join key's column #, or zero */ Oid skewColType; /* datatype of the outer key column */ int32 skewColTypmod; /* typmod of the outer key column */ + int num_buckets; /* just for EXPLAIN */ + int num_batches; /* just for EXPLAIN */ /* all other info is in the parent HashJoin node */ } Hash; *** a/src/include/nodes/relation.h --- b/src/include/nodes/relation.h *************** *** 845,850 **** typedef struct HashPath --- 845,851 ---- { JoinPath jpath; List *path_hashclauses; /* join clauses used for hashing */ + int num_buckets; /* number of buckets expected */ int num_batches; /* number of batches expected */ } HashPath;
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers