aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-08-22 00:16:04 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-08-22 00:16:04 +0000
commitbd3daddaf232d95b0c9ba6f99b0170a0147dd8af (patch)
tree8a64067729f1154120251984e823cdfaa1b0a080 /src/backend/optimizer/util
parent8875a16ee15d6bed09b8f95e813eb74cb8d22fe9 (diff)
downloadpostgresql-bd3daddaf232d95b0c9ba6f99b0170a0147dd8af.tar.gz
postgresql-bd3daddaf232d95b0c9ba6f99b0170a0147dd8af.zip
Arrange to convert EXISTS subqueries that are equivalent to hashable IN
subqueries into the same thing you'd have gotten from IN (except always with unknownEqFalse = true, so as to get the proper semantics for an EXISTS). I believe this fixes the last case within CVS HEAD in which an EXISTS could give worse performance than an equivalent IN subquery. The tricky part of this is that if the upper query probes the EXISTS for only a few rows, the hashing implementation can actually be worse than the default, and therefore we need to make a cost-based decision about which way to use. But at the time when the planner generates plans for subqueries, it doesn't really know how many times the subquery will be executed. The least invasive solution seems to be to generate both plans and postpone the choice until execution. Therefore, in a query that has been optimized this way, EXPLAIN will show two subplans for the EXISTS, of which only one will actually get executed. There is a lot more that could be done based on this infrastructure: in particular it's interesting to consider switching to the hash plan if we start out using the non-hashed plan but find a lot more upper rows going by than we expected. I have therefore left some minor inefficiencies in place, such as initializing both subplans even though we will currently only use one.
Diffstat (limited to 'src/backend/optimizer/util')
-rw-r--r--src/backend/optimizer/util/clauses.c26
-rw-r--r--src/backend/optimizer/util/var.c6
2 files changed, 26 insertions, 6 deletions
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index ffe31bdff28..6a06b0806c2 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.262 2008/08/14 18:47:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.263 2008/08/22 00:16:04 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -360,7 +360,7 @@ make_ands_implicit(Expr *clause)
* are no subqueries. There mustn't be outer-aggregate references either.
*
* (If you want something like this but able to deal with subqueries,
- * see rewriteManip.c's checkExprHasAggs().)
+ * see rewriteManip.c's contain_aggs_of_level().)
*/
bool
contain_agg_clause(Node *clause)
@@ -566,6 +566,8 @@ expression_returns_set_walker(Node *node, void *context)
return false;
if (IsA(node, SubPlan))
return false;
+ if (IsA(node, AlternativeSubPlan))
+ return false;
if (IsA(node, ArrayExpr))
return false;
if (IsA(node, RowExpr))
@@ -637,6 +639,8 @@ expression_returns_set_rows_walker(Node *node, double *count)
return false;
if (IsA(node, SubPlan))
return false;
+ if (IsA(node, AlternativeSubPlan))
+ return false;
if (IsA(node, ArrayExpr))
return false;
if (IsA(node, RowExpr))
@@ -684,6 +688,7 @@ contain_subplans_walker(Node *node, void *context)
if (node == NULL)
return false;
if (IsA(node, SubPlan) ||
+ IsA(node, AlternativeSubPlan) ||
IsA(node, SubLink))
return true; /* abort the tree traversal and return true */
return expression_tree_walker(node, contain_subplans_walker, context);
@@ -1012,6 +1017,8 @@ contain_nonstrict_functions_walker(Node *node, void *context)
}
if (IsA(node, SubPlan))
return true;
+ if (IsA(node, AlternativeSubPlan))
+ return true;
/* ArrayCoerceExpr is strict at the array level, regardless of elemfunc */
if (IsA(node, FieldStore))
return true;
@@ -2308,7 +2315,8 @@ eval_const_expressions_mutator(Node *node,
break;
}
}
- if (IsA(node, SubPlan))
+ if (IsA(node, SubPlan) ||
+ IsA(node, AlternativeSubPlan))
{
/*
* Return a SubPlan unchanged --- too late to do anything with it.
@@ -4156,6 +4164,8 @@ expression_tree_walker(Node *node,
return true;
}
break;
+ case T_AlternativeSubPlan:
+ return walker(((AlternativeSubPlan *) node)->subplans, context);
case T_FieldSelect:
return walker(((FieldSelect *) node)->arg, context);
case T_FieldStore:
@@ -4630,6 +4640,16 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
+ case T_AlternativeSubPlan:
+ {
+ AlternativeSubPlan *asplan = (AlternativeSubPlan *) node;
+ AlternativeSubPlan *newnode;
+
+ FLATCOPY(newnode, asplan, AlternativeSubPlan);
+ MUTATE(newnode->subplans, asplan->subplans, List *);
+ return (Node *) newnode;
+ }
+ break;
case T_FieldSelect:
{
FieldSelect *fselect = (FieldSelect *) node;
diff --git a/src/backend/optimizer/util/var.c b/src/backend/optimizer/util/var.c
index 290f9bb64bf..f9bd59c799b 100644
--- a/src/backend/optimizer/util/var.c
+++ b/src/backend/optimizer/util/var.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.75 2008/08/14 18:47:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/var.c,v 1.76 2008/08/22 00:16:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -171,7 +171,7 @@ pull_varattnos_walker(Node *node, Bitmapset **varattnos)
}
/* Should not find a subquery or subplan */
Assert(!IsA(node, Query));
- Assert(!is_subplan(node));
+ Assert(!IsA(node, SubPlan));
return expression_tree_walker(node, pull_varattnos_walker,
(void *) varattnos);
@@ -677,7 +677,7 @@ flatten_join_alias_vars_mutator(Node *node,
return (Node *) newnode;
}
/* Already-planned tree not supported */
- Assert(!is_subplan(node));
+ Assert(!IsA(node, SubPlan));
return expression_tree_mutator(node, flatten_join_alias_vars_mutator,
(void *) context);