aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2009-03-21 00:04:40 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2009-03-21 00:04:40 +0000
commit596efd27edce20bba706f50de99a0f15bcc2a567 (patch)
tree63c07c3c310e1b072f0a29a79220c81254dba3d8 /src/backend/optimizer
parent249d936bed069877923f0369bd2ce51a6f8f925e (diff)
downloadpostgresql-596efd27edce20bba706f50de99a0f15bcc2a567.tar.gz
postgresql-596efd27edce20bba706f50de99a0f15bcc2a567.zip
Optimize multi-batch hash joins when the outer relation has a nonuniform
distribution, by creating a special fast path for the (first few) most common values of the outer relation. Tuples having hashvalues matching the MCVs are effectively forced to be in the first batch, so that we never write them out to the batch temp files. Bryce Cutt and Ramon Lawrence, with some editorialization by me.
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r--src/backend/optimizer/path/costsize.c18
-rw-r--r--src/backend/optimizer/plan/createplan.c62
2 files changed, 73 insertions, 7 deletions
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 07ddf43c8d6..b07a2599bbe 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -54,7 +54,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.204 2009/02/06 23:43:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.205 2009/03/21 00:04:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1821,6 +1821,7 @@ cost_hashjoin(HashPath *path, PlannerInfo *root, SpecialJoinInfo *sjinfo)
int num_hashclauses = list_length(hashclauses);
int numbuckets;
int numbatches;
+ int num_skew_mcvs;
double virtualbuckets;
Selectivity innerbucketsize;
ListCell *hcl;
@@ -1862,11 +1863,22 @@ cost_hashjoin(HashPath *path, PlannerInfo *root, SpecialJoinInfo *sjinfo)
* inner_path_rows;
run_cost += cpu_operator_cost * num_hashclauses * outer_path_rows;
- /* Get hash table size that executor would use for inner relation */
+ /*
+ * Get hash table size that executor would use for inner relation.
+ *
+ * XXX for the moment, always assume that skew optimization will be
+ * performed. As long as SKEW_WORK_MEM_PERCENT is small, it's not worth
+ * trying to determine that for sure.
+ *
+ * XXX at some point it might be interesting to try to account for skew
+ * optimization in the cost estimate, but for now, we don't.
+ */
ExecChooseHashTableSize(inner_path_rows,
inner_path->parent->width,
+ true, /* useskew */
&numbuckets,
- &numbatches);
+ &numbatches,
+ &num_skew_mcvs);
virtualbuckets = (double) numbuckets *(double) numbatches;
/*
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index a243ca80d2d..be4d79f1bf2 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.255 2009/01/01 17:23:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.256 2009/03/21 00:04:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -112,7 +112,11 @@ static HashJoin *make_hashjoin(List *tlist,
List *hashclauses,
Plan *lefttree, Plan *righttree,
JoinType jointype);
-static Hash *make_hash(Plan *lefttree);
+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,
@@ -1864,6 +1868,10 @@ create_hashjoin_plan(PlannerInfo *root,
List *joinclauses;
List *otherclauses;
List *hashclauses;
+ Oid skewTable = InvalidOid;
+ AttrNumber skewColumn = InvalidAttrNumber;
+ Oid skewColType = InvalidOid;
+ int32 skewColTypmod = -1;
HashJoin *join_plan;
Hash *hash_plan;
@@ -1903,9 +1911,46 @@ create_hashjoin_plan(PlannerInfo *root,
disuse_physical_tlist(inner_plan, best_path->jpath.innerjoinpath);
/*
+ * If there is a single join clause and we can identify the outer
+ * variable as a simple column reference, supply its identity for
+ * possible use in skew optimization. (Note: in principle we could
+ * do skew optimization with multiple join clauses, but we'd have to
+ * be able to determine the most common combinations of outer values,
+ * which we don't currently have enough stats for.)
+ */
+ if (list_length(hashclauses) == 1)
+ {
+ OpExpr *clause = (OpExpr *) linitial(hashclauses);
+ Node *node;
+
+ Assert(is_opclause(clause));
+ node = (Node *) linitial(clause->args);
+ if (IsA(node, RelabelType))
+ node = (Node *) ((RelabelType *) node)->arg;
+ if (IsA(node, Var))
+ {
+ Var *var = (Var *) node;
+ RangeTblEntry *rte;
+
+ rte = root->simple_rte_array[var->varno];
+ if (rte->rtekind == RTE_RELATION)
+ {
+ skewTable = rte->relid;
+ skewColumn = var->varattno;
+ skewColType = var->vartype;
+ skewColTypmod = var->vartypmod;
+ }
+ }
+ }
+
+ /*
* Build the hash node and hash join node.
*/
- hash_plan = make_hash(inner_plan);
+ hash_plan = make_hash(inner_plan,
+ skewTable,
+ skewColumn,
+ skewColType,
+ skewColTypmod);
join_plan = make_hashjoin(tlist,
joinclauses,
otherclauses,
@@ -2713,7 +2758,11 @@ make_hashjoin(List *tlist,
}
static Hash *
-make_hash(Plan *lefttree)
+make_hash(Plan *lefttree,
+ Oid skewTable,
+ AttrNumber skewColumn,
+ Oid skewColType,
+ int32 skewColTypmod)
{
Hash *node = makeNode(Hash);
Plan *plan = &node->plan;
@@ -2730,6 +2779,11 @@ make_hash(Plan *lefttree)
plan->lefttree = lefttree;
plan->righttree = NULL;
+ node->skewTable = skewTable;
+ node->skewColumn = skewColumn;
+ node->skewColType = skewColType;
+ node->skewColTypmod = skewColTypmod;
+
return node;
}