@@ -1045,7 +1045,6 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
10451045 double sub_limit_tuples ;
10461046 AttrNumber * groupColIdx = NULL ;
10471047 bool need_tlist_eval = true;
1048- QualCost tlist_cost ;
10491048 Path * cheapest_path ;
10501049 Path * sorted_path ;
10511050 Path * best_path ;
@@ -1355,27 +1354,9 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
13551354
13561355 /*
13571356 * Also, account for the cost of evaluation of the sub_tlist.
1358- *
1359- * Up to now, we have only been dealing with "flat" tlists,
1360- * containing just Vars. So their evaluation cost is zero
1361- * according to the model used by cost_qual_eval() (or if you
1362- * prefer, the cost is factored into cpu_tuple_cost). Thus we
1363- * can avoid accounting for tlist cost throughout
1364- * query_planner() and subroutines. But now we've inserted a
1365- * tlist that might contain actual operators, sub-selects, etc
1366- * --- so we'd better account for its cost.
1367- *
1368- * Below this point, any tlist eval cost for added-on nodes
1369- * should be accounted for as we create those nodes.
1370- * Presently, of the node types we can add on, only Agg,
1371- * WindowAgg, and Group project new tlists (the rest just copy
1372- * their input tuples) --- so make_agg(), make_windowagg() and
1373- * make_group() are responsible for computing the added cost.
1357+ * See comments for add_tlist_costs_to_plan() for more info.
13741358 */
1375- cost_qual_eval (& tlist_cost , sub_tlist , root );
1376- result_plan -> startup_cost += tlist_cost .startup ;
1377- result_plan -> total_cost += tlist_cost .startup +
1378- tlist_cost .per_tuple * result_plan -> plan_rows ;
1359+ add_tlist_costs_to_plan (root , result_plan , sub_tlist );
13791360 }
13801361 else
13811362 {
@@ -1815,6 +1796,61 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
18151796 return result_plan ;
18161797}
18171798
1799+ /*
1800+ * add_tlist_costs_to_plan
1801+ *
1802+ * Estimate the execution costs associated with evaluating the targetlist
1803+ * expressions, and add them to the cost estimates for the Plan node.
1804+ *
1805+ * If the tlist contains set-returning functions, also inflate the Plan's cost
1806+ * and plan_rows estimates accordingly. (Hence, this must be called *after*
1807+ * any logic that uses plan_rows to, eg, estimate qual evaluation costs.)
1808+ *
1809+ * Note: during initial stages of planning, we mostly consider plan nodes with
1810+ * "flat" tlists, containing just Vars. So their evaluation cost is zero
1811+ * according to the model used by cost_qual_eval() (or if you prefer, the cost
1812+ * is factored into cpu_tuple_cost). Thus we can avoid accounting for tlist
1813+ * cost throughout query_planner() and subroutines. But once we apply a
1814+ * tlist that might contain actual operators, sub-selects, etc, we'd better
1815+ * account for its cost. Any set-returning functions in the tlist must also
1816+ * affect the estimated rowcount.
1817+ *
1818+ * Once grouping_planner() has applied a general tlist to the topmost
1819+ * scan/join plan node, any tlist eval cost for added-on nodes should be
1820+ * accounted for as we create those nodes. Presently, of the node types we
1821+ * can add on later, only Agg, WindowAgg, and Group project new tlists (the
1822+ * rest just copy their input tuples) --- so make_agg(), make_windowagg() and
1823+ * make_group() are responsible for calling this function to account for their
1824+ * tlist costs.
1825+ */
1826+ void
1827+ add_tlist_costs_to_plan (PlannerInfo * root , Plan * plan , List * tlist )
1828+ {
1829+ QualCost tlist_cost ;
1830+ double tlist_rows ;
1831+
1832+ cost_qual_eval (& tlist_cost , tlist , root );
1833+ plan -> startup_cost += tlist_cost .startup ;
1834+ plan -> total_cost += tlist_cost .startup +
1835+ tlist_cost .per_tuple * plan -> plan_rows ;
1836+
1837+ tlist_rows = tlist_returns_set_rows (tlist );
1838+ if (tlist_rows > 1 )
1839+ {
1840+ /*
1841+ * We assume that execution costs of the tlist proper were all
1842+ * accounted for by cost_qual_eval. However, it still seems
1843+ * appropriate to charge something more for the executor's general
1844+ * costs of processing the added tuples. The cost is probably less
1845+ * than cpu_tuple_cost, though, so we arbitrarily use half of that.
1846+ */
1847+ plan -> total_cost += plan -> plan_rows * (tlist_rows - 1 ) *
1848+ cpu_tuple_cost / 2 ;
1849+
1850+ plan -> plan_rows *= tlist_rows ;
1851+ }
1852+ }
1853+
18181854/*
18191855 * Detect whether a plan node is a "dummy" plan created when a relation
18201856 * is deemed not to need scanning due to constraint exclusion.
0 commit comments