diff options
author | Etsuro Fujita <efujita@postgresql.org> | 2019-05-09 18:39:23 +0900 |
---|---|---|
committer | Etsuro Fujita <efujita@postgresql.org> | 2019-05-09 18:39:23 +0900 |
commit | edbcbe277d795ecc339b0e4fa29bae42ce1a7be9 (patch) | |
tree | 54f2a822cf33f9dbe451c771a8799b9ba1477097 | |
parent | 47a338cfcd67139a1f91892b080934fcfc3aea03 (diff) | |
download | postgresql-edbcbe277d795ecc339b0e4fa29bae42ce1a7be9.tar.gz postgresql-edbcbe277d795ecc339b0e4fa29bae42ce1a7be9.zip |
postgres_fdw: Fix cost estimation for aggregate pushdown.
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
-rw-r--r-- | contrib/postgres_fdw/postgres_fdw.c | 16 | ||||
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 4 |
2 files changed, 17 insertions, 3 deletions
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 6c9e320af99..4cbfb12a664 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -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; diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index eb6f5a354dc..48005434d40 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -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); |