mirror of
https://github.com/postgres/postgres.git
synced 2025-07-12 21:01:52 +03:00
Fix performance issue with qualifications on VIEWs: outer query should
try to push restrictions on the view down into the view subquery, so that they can become indexscan quals or what-have-you rather than being applied at the top level of the subquery. 7.0 and before were able to do this, though in a much klugier way, and I'd hate to have anyone complaining that 7.1 is stupider than 7.0 ...
This commit is contained in:
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.98 2000/12/14 22:30:43 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.99 2001/01/18 07:12:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -132,6 +132,7 @@ subquery_planner(Query *parse, double tuple_fraction)
|
||||
List *saved_initplan = PlannerInitPlan;
|
||||
int saved_planid = PlannerPlanId;
|
||||
Plan *plan;
|
||||
List *newHaving;
|
||||
List *lst;
|
||||
|
||||
/* Set up for a new level of subquery */
|
||||
@ -155,20 +156,6 @@ subquery_planner(Query *parse, double tuple_fraction)
|
||||
parse->jointree = (FromExpr *)
|
||||
preprocess_jointree(parse, (Node *) parse->jointree);
|
||||
|
||||
/*
|
||||
* A HAVING clause without aggregates is equivalent to a WHERE clause
|
||||
* (except it can only refer to grouped fields). If there are no aggs
|
||||
* anywhere in the query, then we don't want to create an Agg plan
|
||||
* node, so merge the HAVING condition into WHERE. (We used to
|
||||
* consider this an error condition, but it seems to be legal SQL.)
|
||||
*/
|
||||
if (parse->havingQual != NULL && !parse->hasAggs)
|
||||
{
|
||||
parse->jointree->quals = make_and_qual(parse->jointree->quals,
|
||||
parse->havingQual);
|
||||
parse->havingQual = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Do expression preprocessing on targetlist and quals.
|
||||
*/
|
||||
@ -181,6 +168,37 @@ subquery_planner(Query *parse, double tuple_fraction)
|
||||
parse->havingQual = preprocess_expression(parse, parse->havingQual,
|
||||
EXPRKIND_HAVING);
|
||||
|
||||
/*
|
||||
* A HAVING clause without aggregates is equivalent to a WHERE clause
|
||||
* (except it can only refer to grouped fields). Transfer any agg-free
|
||||
* clauses of the HAVING qual into WHERE. This may seem like wasting
|
||||
* cycles to cater to stupidly-written queries, but there are other
|
||||
* reasons for doing it. Firstly, if the query contains no aggs at all,
|
||||
* then we aren't going to generate an Agg plan node, and so there'll be
|
||||
* no place to execute HAVING conditions; without this transfer, we'd
|
||||
* lose the HAVING condition entirely, which is wrong. Secondly, when
|
||||
* we push down a qual condition into a sub-query, it's easiest to push
|
||||
* the qual into HAVING always, in case it contains aggs, and then let
|
||||
* this code sort it out.
|
||||
*
|
||||
* Note that both havingQual and parse->jointree->quals are in
|
||||
* implicitly-ANDed-list form at this point, even though they are
|
||||
* declared as Node *. Also note that contain_agg_clause does not
|
||||
* recurse into sub-selects, which is exactly what we need here.
|
||||
*/
|
||||
newHaving = NIL;
|
||||
foreach(lst, (List *) parse->havingQual)
|
||||
{
|
||||
Node *havingclause = (Node *) lfirst(lst);
|
||||
|
||||
if (contain_agg_clause(havingclause))
|
||||
newHaving = lappend(newHaving, havingclause);
|
||||
else
|
||||
parse->jointree->quals = (Node *)
|
||||
lappend((List *) parse->jointree->quals, havingclause);
|
||||
}
|
||||
parse->havingQual = (Node *) newHaving;
|
||||
|
||||
/*
|
||||
* Do the main planning. If we have an inherited target relation,
|
||||
* that needs special processing, else go straight to grouping_planner.
|
||||
@ -554,12 +572,6 @@ preprocess_expression(Query *parse, Node *expr, int kind)
|
||||
* Check for ungrouped variables passed to subplans. Note we
|
||||
* do NOT do this for subplans in WHERE (or JOIN/ON); it's legal
|
||||
* there because WHERE is evaluated pre-GROUP.
|
||||
*
|
||||
* An interesting fine point: if subquery_planner reassigned a
|
||||
* HAVING qual into WHERE, then we will accept references to
|
||||
* ungrouped vars from subplans in the HAVING qual. This is not
|
||||
* entirely consistent, but it doesn't seem particularly
|
||||
* harmful...
|
||||
*/
|
||||
check_subplans_for_ungrouped_vars(expr, parse);
|
||||
}
|
||||
@ -1049,6 +1061,11 @@ grouping_planner(Query *parse, double tuple_fraction)
|
||||
result_plan);
|
||||
/* Note: Agg does not affect any existing sort order of the tuples */
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If there are no Aggs, we shouldn't have any HAVING qual anymore */
|
||||
Assert(parse->havingQual == NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* If we were not able to make the plan come out in the right order,
|
||||
|
Reference in New Issue
Block a user