aboutsummaryrefslogtreecommitdiff
path: root/contrib/postgres_fdw
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2024-08-21 10:12:30 -0400
committerRobert Haas <rhaas@postgresql.org>2024-08-21 10:12:30 -0400
commite22253467942fdb100087787c3e1e3a8620c54b2 (patch)
tree879d77c5fd4157f6867ded7a3ed682d67177c49b /contrib/postgres_fdw
parent2b03cfeea47834913ff769124f4deba88140f662 (diff)
downloadpostgresql-e22253467942fdb100087787c3e1e3a8620c54b2.tar.gz
postgresql-e22253467942fdb100087787c3e1e3a8620c54b2.zip
Treat number of disabled nodes in a path as a separate cost metric.
Previously, when a path type was disabled by e.g. enable_seqscan=false, we either avoided generating that path type in the first place, or more commonly, we added a large constant, called disable_cost, to the estimated startup cost of that path. This latter approach can distort planning. For instance, an extremely expensive non-disabled path could seem to be worse than a disabled path, especially if the full cost of that path node need not be paid (e.g. due to a Limit). Or, as in the regression test whose expected output changes with this commit, the addition of disable_cost can make two paths that would normally be distinguishible in cost seem to have fuzzily the same cost. To fix that, we now count the number of disabled path nodes and consider that a high-order component of both the startup cost and the total cost. Hence, the path list is now sorted by disabled_nodes and then by total_cost, instead of just by the latter, and likewise for the partial path list. It is important that this number is a count and not simply a Boolean; else, as soon as we're unable to respect disabled path types in all portions of the path, we stop trying to avoid them where we can. Because the path list is now sorted by the number of disabled nodes, the join prechecks must compute the count of disabled nodes during the initial cost phase instead of postponing it to final cost time. Counts of disabled nodes do not cross subquery levels; at present, there is no reason for them to do so, since the we do not postpone path selection across subquery boundaries (see make_subplan). Reviewed by Andres Freund, Heikki Linnakangas, and David Rowley. Discussion: http://postgr.es/m/CA+TgmoZ_+MS+o6NeGK2xyBv-xM+w1AfFVuHE4f_aq6ekHv7YSQ@mail.gmail.com
Diffstat (limited to 'contrib/postgres_fdw')
-rw-r--r--contrib/postgres_fdw/postgres_fdw.c46
-rw-r--r--contrib/postgres_fdw/postgres_fdw.h1
2 files changed, 40 insertions, 7 deletions
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index fc65d81e217..adc62576d1f 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -430,6 +430,7 @@ static void estimate_path_cost_size(PlannerInfo *root,
List *pathkeys,
PgFdwPathExtraData *fpextra,
double *p_rows, int *p_width,
+ int *p_disabled_nodes,
Cost *p_startup_cost, Cost *p_total_cost);
static void get_remote_estimate(const char *sql,
PGconn *conn,
@@ -442,6 +443,7 @@ static void adjust_foreign_grouping_path_cost(PlannerInfo *root,
double retrieved_rows,
double width,
double limit_tuples,
+ int *disabled_nodes,
Cost *p_startup_cost,
Cost *p_run_cost);
static bool ec_member_matches_foreign(PlannerInfo *root, RelOptInfo *rel,
@@ -735,6 +737,7 @@ postgresGetForeignRelSize(PlannerInfo *root,
*/
estimate_path_cost_size(root, baserel, NIL, NIL, NULL,
&fpinfo->rows, &fpinfo->width,
+ &fpinfo->disabled_nodes,
&fpinfo->startup_cost, &fpinfo->total_cost);
/* Report estimated baserel size to planner. */
@@ -765,6 +768,7 @@ postgresGetForeignRelSize(PlannerInfo *root,
/* Fill in basically-bogus cost estimates for use later. */
estimate_path_cost_size(root, baserel, NIL, NIL, NULL,
&fpinfo->rows, &fpinfo->width,
+ &fpinfo->disabled_nodes,
&fpinfo->startup_cost, &fpinfo->total_cost);
}
@@ -1030,6 +1034,7 @@ postgresGetForeignPaths(PlannerInfo *root,
path = create_foreignscan_path(root, baserel,
NULL, /* default pathtarget */
fpinfo->rows,
+ fpinfo->disabled_nodes,
fpinfo->startup_cost,
fpinfo->total_cost,
NIL, /* no pathkeys */
@@ -1184,13 +1189,14 @@ postgresGetForeignPaths(PlannerInfo *root,
ParamPathInfo *param_info = (ParamPathInfo *) lfirst(lc);
double rows;
int width;
+ int disabled_nodes;
Cost startup_cost;
Cost total_cost;
/* Get a cost estimate from the remote */
estimate_path_cost_size(root, baserel,
param_info->ppi_clauses, NIL, NULL,
- &rows, &width,
+ &rows, &width, &disabled_nodes,
&startup_cost, &total_cost);
/*
@@ -1203,6 +1209,7 @@ postgresGetForeignPaths(PlannerInfo *root,
path = create_foreignscan_path(root, baserel,
NULL, /* default pathtarget */
rows,
+ disabled_nodes,
startup_cost,
total_cost,
NIL, /* no pathkeys */
@@ -3079,7 +3086,7 @@ postgresExecForeignTruncate(List *rels,
* final sort and the LIMIT restriction.
*
* The function returns the cost and size estimates in p_rows, p_width,
- * p_startup_cost and p_total_cost variables.
+ * p_disabled_nodes, p_startup_cost and p_total_cost variables.
*/
static void
estimate_path_cost_size(PlannerInfo *root,
@@ -3088,12 +3095,14 @@ estimate_path_cost_size(PlannerInfo *root,
List *pathkeys,
PgFdwPathExtraData *fpextra,
double *p_rows, int *p_width,
+ int *p_disabled_nodes,
Cost *p_startup_cost, Cost *p_total_cost)
{
PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
double rows;
double retrieved_rows;
int width;
+ int disabled_nodes = 0;
Cost startup_cost;
Cost total_cost;
@@ -3483,6 +3492,7 @@ estimate_path_cost_size(PlannerInfo *root,
adjust_foreign_grouping_path_cost(root, pathkeys,
retrieved_rows, width,
fpextra->limit_tuples,
+ &disabled_nodes,
&startup_cost, &run_cost);
}
else
@@ -3577,6 +3587,7 @@ estimate_path_cost_size(PlannerInfo *root,
/* Return results. */
*p_rows = rows;
*p_width = width;
+ *p_disabled_nodes = disabled_nodes;
*p_startup_cost = startup_cost;
*p_total_cost = total_cost;
}
@@ -3637,6 +3648,7 @@ adjust_foreign_grouping_path_cost(PlannerInfo *root,
double retrieved_rows,
double width,
double limit_tuples,
+ int *p_disabled_nodes,
Cost *p_startup_cost,
Cost *p_run_cost)
{
@@ -3656,6 +3668,7 @@ adjust_foreign_grouping_path_cost(PlannerInfo *root,
cost_sort(&sort_path,
root,
pathkeys,
+ 0,
*p_startup_cost + *p_run_cost,
retrieved_rows,
width,
@@ -6147,13 +6160,15 @@ add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
{
double rows;
int width;
+ int disabled_nodes;
Cost startup_cost;
Cost total_cost;
List *useful_pathkeys = lfirst(lc);
Path *sorted_epq_path;
estimate_path_cost_size(root, rel, NIL, useful_pathkeys, NULL,
- &rows, &width, &startup_cost, &total_cost);
+ &rows, &width, &disabled_nodes,
+ &startup_cost, &total_cost);
/*
* The EPQ path must be at least as well sorted as the path itself, in
@@ -6175,6 +6190,7 @@ add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
create_foreignscan_path(root, rel,
NULL,
rows,
+ disabled_nodes,
startup_cost,
total_cost,
useful_pathkeys,
@@ -6188,6 +6204,7 @@ add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
create_foreign_join_path(root, rel,
NULL,
rows,
+ disabled_nodes,
startup_cost,
total_cost,
useful_pathkeys,
@@ -6335,6 +6352,7 @@ postgresGetForeignJoinPaths(PlannerInfo *root,
ForeignPath *joinpath;
double rows;
int width;
+ int disabled_nodes;
Cost startup_cost;
Cost total_cost;
Path *epq_path; /* Path to create plan to be executed when
@@ -6424,12 +6442,14 @@ postgresGetForeignJoinPaths(PlannerInfo *root,
/* Estimate costs for bare join relation */
estimate_path_cost_size(root, joinrel, NIL, NIL, NULL,
- &rows, &width, &startup_cost, &total_cost);
+ &rows, &width, &disabled_nodes,
+ &startup_cost, &total_cost);
/* Now update this information in the joinrel */
joinrel->rows = rows;
joinrel->reltarget->width = width;
fpinfo->rows = rows;
fpinfo->width = width;
+ fpinfo->disabled_nodes = disabled_nodes;
fpinfo->startup_cost = startup_cost;
fpinfo->total_cost = total_cost;
@@ -6441,6 +6461,7 @@ postgresGetForeignJoinPaths(PlannerInfo *root,
joinrel,
NULL, /* default pathtarget */
rows,
+ disabled_nodes,
startup_cost,
total_cost,
NIL, /* no pathkeys */
@@ -6768,6 +6789,7 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
ForeignPath *grouppath;
double rows;
int width;
+ int disabled_nodes;
Cost startup_cost;
Cost total_cost;
@@ -6818,11 +6840,13 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
/* Estimate the cost of push down */
estimate_path_cost_size(root, grouped_rel, NIL, NIL, NULL,
- &rows, &width, &startup_cost, &total_cost);
+ &rows, &width, &disabled_nodes,
+ &startup_cost, &total_cost);
/* Now update this information in the fpinfo */
fpinfo->rows = rows;
fpinfo->width = width;
+ fpinfo->disabled_nodes = disabled_nodes;
fpinfo->startup_cost = startup_cost;
fpinfo->total_cost = total_cost;
@@ -6831,6 +6855,7 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
grouped_rel,
grouped_rel->reltarget,
rows,
+ disabled_nodes,
startup_cost,
total_cost,
NIL, /* no pathkeys */
@@ -6859,6 +6884,7 @@ add_foreign_ordered_paths(PlannerInfo *root, RelOptInfo *input_rel,
PgFdwPathExtraData *fpextra;
double rows;
int width;
+ int disabled_nodes;
Cost startup_cost;
Cost total_cost;
List *fdw_private;
@@ -6952,7 +6978,8 @@ add_foreign_ordered_paths(PlannerInfo *root, RelOptInfo *input_rel,
/* Estimate the costs of performing the final sort remotely */
estimate_path_cost_size(root, input_rel, NIL, root->sort_pathkeys, fpextra,
- &rows, &width, &startup_cost, &total_cost);
+ &rows, &width, &disabled_nodes,
+ &startup_cost, &total_cost);
/*
* Build the fdw_private list that will be used by postgresGetForeignPlan.
@@ -6965,6 +6992,7 @@ add_foreign_ordered_paths(PlannerInfo *root, RelOptInfo *input_rel,
input_rel,
root->upper_targets[UPPERREL_ORDERED],
rows,
+ disabled_nodes,
startup_cost,
total_cost,
root->sort_pathkeys,
@@ -6998,6 +7026,7 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
bool save_use_remote_estimate = false;
double rows;
int width;
+ int disabled_nodes;
Cost startup_cost;
Cost total_cost;
List *fdw_private;
@@ -7082,6 +7111,7 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
path->parent,
path->pathtarget,
path->rows,
+ path->disabled_nodes,
path->startup_cost,
path->total_cost,
path->pathkeys,
@@ -7199,7 +7229,8 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
ifpinfo->use_remote_estimate = false;
}
estimate_path_cost_size(root, input_rel, NIL, pathkeys, fpextra,
- &rows, &width, &startup_cost, &total_cost);
+ &rows, &width, &disabled_nodes,
+ &startup_cost, &total_cost);
if (!fpextra->has_final_sort)
ifpinfo->use_remote_estimate = save_use_remote_estimate;
@@ -7218,6 +7249,7 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
input_rel,
root->upper_targets[UPPERREL_FINAL],
rows,
+ disabled_nodes,
startup_cost,
total_cost,
pathkeys,
diff --git a/contrib/postgres_fdw/postgres_fdw.h b/contrib/postgres_fdw/postgres_fdw.h
index 37c1575af6c..9e501660d18 100644
--- a/contrib/postgres_fdw/postgres_fdw.h
+++ b/contrib/postgres_fdw/postgres_fdw.h
@@ -62,6 +62,7 @@ typedef struct PgFdwRelationInfo
/* Estimated size and cost for a scan, join, or grouping/aggregation. */
double rows;
int width;
+ int disabled_nodes;
Cost startup_cost;
Cost total_cost;