From 8ac6d952cfa98f024a788bd0699dc1c0cd448af0 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 13 Jan 2003 00:29:26 +0000 Subject: [PATCH] Cause planner to account for evaluation costs in targetlists and HAVING quals. Normally this is an insignificant effect --- but it will not be insignificant when these clauses contain sub-selects. The added costs cannot affect the planning of the query containing them, but they might have an impact when the query is a sub-query of a larger one. --- src/backend/optimizer/plan/createplan.c | 57 +++++++++++++++++++++++-- src/backend/optimizer/plan/planner.c | 24 ++++++++++- src/backend/optimizer/plan/subselect.c | 4 +- 3 files changed, 79 insertions(+), 6 deletions(-) diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index a67e23fbf2..3d9ee6e4f4 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.128 2002/12/12 15:49:32 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.129 2003/01/13 00:29:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1366,6 +1366,7 @@ make_subqueryscan(List *qptlist, SubqueryScan *node = makeNode(SubqueryScan); Plan *plan = &node->scan.plan; + /* cost is figured here for the convenience of prepunion.c */ copy_plan_costsize(plan, subplan); plan->targetlist = qptlist; plan->qual = qpqual; @@ -1488,7 +1489,7 @@ make_hash(List *tlist, List *hashkeys, Plan *lefttree) */ plan->startup_cost = plan->total_cost; plan->targetlist = tlist; - plan->qual = NULL; + plan->qual = NIL; plan->lefttree = lefttree; plan->righttree = NULL; node->hashkeys = hashkeys; @@ -1646,6 +1647,7 @@ make_agg(Query *root, List *tlist, List *qual, Agg *node = makeNode(Agg); Plan *plan = &node->plan; Path agg_path; /* dummy for result of cost_agg */ + QualCost qual_cost; node->aggstrategy = aggstrategy; node->numCols = numGroupCols; @@ -1671,6 +1673,27 @@ make_agg(Query *root, List *tlist, List *qual, else plan->plan_rows = numGroups; + /* + * We also need to account for the cost of evaluation of the qual + * (ie, the HAVING clause) and the tlist. Note that cost_qual_eval + * doesn't charge anything for Aggref nodes; this is okay since + * they are really comparable to Vars. + * + * See notes in grouping_planner about why this routine and make_group + * are the only ones in this file that worry about tlist eval cost. + */ + if (qual) + { + cost_qual_eval(&qual_cost, qual); + plan->startup_cost += qual_cost.startup; + plan->total_cost += qual_cost.startup; + plan->total_cost += qual_cost.per_tuple * plan->plan_rows; + } + cost_qual_eval(&qual_cost, tlist); + plan->startup_cost += qual_cost.startup; + plan->total_cost += qual_cost.startup; + plan->total_cost += qual_cost.per_tuple * plan->plan_rows; + plan->qual = qual; plan->targetlist = tlist; plan->lefttree = lefttree; @@ -1690,6 +1713,7 @@ make_group(Query *root, Group *node = makeNode(Group); Plan *plan = &node->plan; Path group_path; /* dummy for result of cost_group */ + QualCost qual_cost; node->numCols = numGroupCols; node->grpColIdx = grpColIdx; @@ -1706,7 +1730,23 @@ make_group(Query *root, /* One output tuple per estimated result group */ plan->plan_rows = numGroups; - plan->qual = NULL; + /* + * We also need to account for the cost of evaluation of the tlist. + * + * XXX this double-counts the cost of evaluation of any expressions + * used for grouping, since in reality those will have been evaluated + * at a lower plan level and will only be copied by the Group node. + * Worth fixing? + * + * See notes in grouping_planner about why this routine and make_agg + * are the only ones in this file that worry about tlist eval cost. + */ + cost_qual_eval(&qual_cost, tlist); + plan->startup_cost += qual_cost.startup; + plan->total_cost += qual_cost.startup; + plan->total_cost += qual_cost.per_tuple * plan->plan_rows; + + plan->qual = NIL; plan->targetlist = tlist; plan->lefttree = lefttree; plan->righttree = (Plan *) NULL; @@ -1718,7 +1758,6 @@ make_group(Query *root, * distinctList is a list of SortClauses, identifying the targetlist items * that should be considered by the Unique filter. */ - Unique * make_unique(List *tlist, Plan *lefttree, List *distinctList) { @@ -1911,6 +1950,16 @@ make_result(List *tlist, plan->plan_width = 0; /* XXX try to be smarter? */ } + if (resconstantqual) + { + QualCost qual_cost; + + cost_qual_eval(&qual_cost, (List *) resconstantqual); + /* resconstantqual is evaluated once at startup */ + plan->startup_cost += qual_cost.startup + qual_cost.per_tuple; + plan->total_cost += qual_cost.startup + qual_cost.per_tuple; + } + plan->targetlist = tlist; plan->qual = NIL; plan->lefttree = subplan; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index e886b88184..3b8981021a 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.136 2002/12/19 23:25:01 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.137 2003/01/13 00:29:25 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -966,6 +966,7 @@ grouping_planner(Query *parse, double tuple_fraction) List *sub_tlist; List *group_pathkeys; AttrNumber *groupColIdx = NULL; + QualCost tlist_cost; double sub_tuple_fraction; Path *cheapest_path; Path *sorted_path; @@ -1452,6 +1453,27 @@ grouping_planner(Query *parse, double tuple_fraction) */ result_plan->targetlist = sub_tlist; } + /* + * Also, account for the cost of evaluation of the sub_tlist. + * + * Up to now, we have only been dealing with "flat" tlists, containing + * just Vars. So their evaluation cost is zero according to the + * model used by cost_qual_eval() (or if you prefer, the cost is + * factored into cpu_tuple_cost). Thus we can avoid accounting for + * tlist cost throughout query_planner() and subroutines. + * But now we've inserted a tlist that might contain actual operators, + * sub-selects, etc --- so we'd better account for its cost. + * + * Below this point, any tlist eval cost for added-on nodes should + * be accounted for as we create those nodes. Presently, of the + * node types we can add on, only Agg and Group project new tlists + * (the rest just copy their input tuples) --- so make_agg() and + * make_group() are responsible for computing the added cost. + */ + cost_qual_eval(&tlist_cost, sub_tlist); + result_plan->startup_cost += tlist_cost.startup; + result_plan->total_cost += tlist_cost.startup + + tlist_cost.per_tuple * result_plan->plan_rows; /* * Insert AGG or GROUP node if needed, plus an explicit sort step diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 2feaff11f7..42da081e05 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.64 2003/01/12 04:03:34 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.65 2003/01/13 00:29:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -378,6 +378,8 @@ make_subplan(SubLink *slink, List *lefthand) plan->plan_width); matplan->startup_cost = matpath.startup_cost; matplan->total_cost = matpath.total_cost; + matplan->plan_rows = plan->plan_rows; + matplan->plan_width = plan->plan_width; /* parameter kluge --- see comments above */ matplan->extParam = listCopy(plan->extParam); matplan->locParam = listCopy(plan->locParam);