]> granicus.if.org Git - postgresql/commitdiff
postgres_fdw: Fix cost estimation for aggregate pushdown.
authorEtsuro Fujita <efujita@postgresql.org>
Thu, 9 May 2019 09:39:23 +0000 (18:39 +0900)
committerEtsuro Fujita <efujita@postgresql.org>
Thu, 9 May 2019 09:39:23 +0000 (18:39 +0900)
In commit 7012b132d0, which added support for aggregate pushdown in
postgres_fdw, the expense of evaluating the final scan/join target
computed by make_group_input_target() was not accounted for at all in
costing aggregate pushdown paths with local statistics.  The right fix
for this would be to have a separate upper stage to adjust the final
scan/join relation (see comments for apply_scanjoin_target_to_paths());
but for now, fix by adding the tlist eval cost when costing aggregate
pushdown paths with local statistics.

Apply this to HEAD only to avoid destabilizing existing plan choices.

Author: Etsuro Fujita
Reviewed-By: Antonin Houska
Discussion: https://postgr.es/m/5C66A056.60007%40lab.ntt.co.jp

contrib/postgres_fdw/postgres_fdw.c
src/backend/optimizer/plan/planner.c

index 6c9e320af990cb000d782b6d9ee60cbdfd7ed422..4cbfb12a66442cb3a4a87abafec07da75093ad19 100644 (file)
@@ -2842,12 +2842,18 @@ estimate_path_cost_size(PlannerInfo *root,
                }
                else if (IS_UPPER_REL(foreignrel))
                {
+                       RelOptInfo *outerrel = fpinfo->outerrel;
                        PgFdwRelationInfo *ofpinfo;
                        AggClauseCosts aggcosts;
                        double          input_rows;
                        int                     numGroupCols;
                        double          numGroups = 1;
 
+                       /* The upper relation should have its outer relation set */
+                       Assert(outerrel);
+                       /* and that outer relation should have its reltarget set */
+                       Assert(outerrel->reltarget);
+
                        /*
                         * This cost model is mixture of costing done for sorted and
                         * hashed aggregates in cost_agg().  We are not sure which
@@ -2856,7 +2862,7 @@ estimate_path_cost_size(PlannerInfo *root,
                         * and all finalization and run cost are added in total_cost.
                         */
 
-                       ofpinfo = (PgFdwRelationInfo *) fpinfo->outerrel->fdw_private;
+                       ofpinfo = (PgFdwRelationInfo *) outerrel->fdw_private;
 
                        /* Get rows and width from input rel */
                        input_rows = ofpinfo->rows;
@@ -2909,11 +2915,13 @@ estimate_path_cost_size(PlannerInfo *root,
 
                        /*-----
                         * Startup cost includes:
-                        *        1. Startup cost for underneath input relation
+                        *        1. Startup cost for underneath input relation, adjusted for
+                        *           tlist replacement by apply_scanjoin_target_to_paths()
                         *        2. Cost of performing aggregation, per cost_agg()
                         *-----
                         */
                        startup_cost = ofpinfo->rel_startup_cost;
+                       startup_cost += outerrel->reltarget->cost.startup;
                        startup_cost += aggcosts.transCost.startup;
                        startup_cost += aggcosts.transCost.per_tuple * input_rows;
                        startup_cost += aggcosts.finalCost.startup;
@@ -2921,11 +2929,13 @@ estimate_path_cost_size(PlannerInfo *root,
 
                        /*-----
                         * Run time cost includes:
-                        *        1. Run time cost of underneath input relation
+                        *        1. Run time cost of underneath input relation, adjusted for
+                        *           tlist replacement by apply_scanjoin_target_to_paths()
                         *        2. Run time cost of performing aggregation, per cost_agg()
                         *-----
                         */
                        run_cost = ofpinfo->rel_total_cost - ofpinfo->rel_startup_cost;
+                       run_cost += outerrel->reltarget->cost.per_tuple * input_rows;
                        run_cost += aggcosts.finalCost.per_tuple * numGroups;
                        run_cost += cpu_tuple_cost * numGroups;
 
index eb6f5a354dc311be8c36525d804f0716a6176dea..48005434d40919831b73d5876ff88b3fd7fb9c1f 100644 (file)
@@ -7113,6 +7113,10 @@ apply_scanjoin_target_to_paths(PlannerInfo *root,
         * confused in createplan.c if they don't agree.  We must do this now so
         * that any append paths made in the next part will use the correct
         * pathtarget (cf. create_append_path).
+        *
+        * Note that this is also necessary if GetForeignUpperPaths() gets called
+        * on the final scan/join relation or on any of its children, since the
+        * FDW might look at the rel's target to create ForeignPaths.
         */
        rel->reltarget = llast_node(PathTarget, scanjoin_targets);