From 8ac6d952cfa98f024a788bd0699dc1c0cd448af0 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
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 a67e23fbf20..3d9ee6e4f4f 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 e886b88184e..3b8981021af 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 2feaff11f75..42da081e059 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);
-- 
GitLab