aboutsummaryrefslogtreecommitdiff
path: root/src/backend/rewrite/rewriteManip.c
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/rewrite/rewriteManip.c
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/rewrite/rewriteManip.c')
-rw-r--r--src/backend/rewrite/rewriteManip.c38
1 files changed, 25 insertions, 13 deletions
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index 1202c31314d..baa9330016f 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.109 2008/08/14 20:31:29 heikki Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.110 2008/08/22 00:16:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -25,10 +25,10 @@
typedef struct
{
int sublevels_up;
-} checkExprHasAggs_context;
+} contain_aggs_of_level_context;
-static bool checkExprHasAggs_walker(Node *node,
- checkExprHasAggs_context *context);
+static bool contain_aggs_of_level_walker(Node *node,
+ contain_aggs_of_level_context *context);
static bool checkExprHasSubLink_walker(Node *node, void *context);
static Relids offset_relid_set(Relids relids, int offset);
static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
@@ -37,32 +37,44 @@ static Relids adjust_relid_set(Relids relids, int oldrelid, int newrelid);
/*
* checkExprHasAggs -
* Check if an expression contains an aggregate function call.
+ */
+bool
+checkExprHasAggs(Node *node)
+{
+ return contain_aggs_of_level(node, 0);
+}
+
+/*
+ * contain_aggs_of_level -
+ * Check if an expression contains an aggregate function call of a
+ * specified query level.
*
* The objective of this routine is to detect whether there are aggregates
- * belonging to the initial query level. Aggregates belonging to subqueries
+ * belonging to the given query level. Aggregates belonging to subqueries
* or outer queries do NOT cause a true result. We must recurse into
* subqueries to detect outer-reference aggregates that logically belong to
- * the initial query level.
+ * the specified query level.
*/
bool
-checkExprHasAggs(Node *node)
+contain_aggs_of_level(Node *node, int levelsup)
{
- checkExprHasAggs_context context;
+ contain_aggs_of_level_context context;
- context.sublevels_up = 0;
+ context.sublevels_up = levelsup;
/*
* Must be prepared to start with a Query or a bare expression tree; if
* it's a Query, we don't want to increment sublevels_up.
*/
return query_or_expression_tree_walker(node,
- checkExprHasAggs_walker,
+ contain_aggs_of_level_walker,
(void *) &context,
0);
}
static bool
-checkExprHasAggs_walker(Node *node, checkExprHasAggs_context *context)
+contain_aggs_of_level_walker(Node *node,
+ contain_aggs_of_level_context *context)
{
if (node == NULL)
return false;
@@ -79,12 +91,12 @@ checkExprHasAggs_walker(Node *node, checkExprHasAggs_context *context)
context->sublevels_up++;
result = query_tree_walker((Query *) node,
- checkExprHasAggs_walker,
+ contain_aggs_of_level_walker,
(void *) context, 0);
context->sublevels_up--;
return result;
}
- return expression_tree_walker(node, checkExprHasAggs_walker,
+ return expression_tree_walker(node, contain_aggs_of_level_walker,
(void *) context);
}