Cause planner to account for evaluation costs in targetlists and
authorTom Lane
Mon, 13 Jan 2003 00:29:26 +0000 (00:29 +0000)
committerTom Lane
Mon, 13 Jan 2003 00:29:26 +0000 (00:29 +0000)
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
src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/subselect.c

index a67e23fbf200a0a49290d1cf0052084ba6bf7927..3d9ee6e4f4f6313c9166c36dcf59880f2acd4c2f 100644 (file)
@@ -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;
index e886b88184e19fbd26375307c85992a91a6e6aee..3b8981021af82d23fd9a52bb1532dfc4d1ec0854 100644 (file)
@@ -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
index 2feaff11f75ea183d75fcb605446ee5c4da266f9..42da081e0596f9890c0fb9f8cb5b3e505c4c66e9 100644 (file)
@@ -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);