mirror of https://github.com/postgres/postgres
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
This commit is contained in:
parent
2b03cfeea4
commit
e222534679
|
@ -576,6 +576,7 @@ fileGetForeignPaths(PlannerInfo *root,
|
||||||
create_foreignscan_path(root, baserel,
|
create_foreignscan_path(root, baserel,
|
||||||
NULL, /* default pathtarget */
|
NULL, /* default pathtarget */
|
||||||
baserel->rows,
|
baserel->rows,
|
||||||
|
0,
|
||||||
startup_cost,
|
startup_cost,
|
||||||
total_cost,
|
total_cost,
|
||||||
NIL, /* no pathkeys */
|
NIL, /* no pathkeys */
|
||||||
|
|
|
@ -430,6 +430,7 @@ static void estimate_path_cost_size(PlannerInfo *root,
|
||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
PgFdwPathExtraData *fpextra,
|
PgFdwPathExtraData *fpextra,
|
||||||
double *p_rows, int *p_width,
|
double *p_rows, int *p_width,
|
||||||
|
int *p_disabled_nodes,
|
||||||
Cost *p_startup_cost, Cost *p_total_cost);
|
Cost *p_startup_cost, Cost *p_total_cost);
|
||||||
static void get_remote_estimate(const char *sql,
|
static void get_remote_estimate(const char *sql,
|
||||||
PGconn *conn,
|
PGconn *conn,
|
||||||
|
@ -442,6 +443,7 @@ static void adjust_foreign_grouping_path_cost(PlannerInfo *root,
|
||||||
double retrieved_rows,
|
double retrieved_rows,
|
||||||
double width,
|
double width,
|
||||||
double limit_tuples,
|
double limit_tuples,
|
||||||
|
int *disabled_nodes,
|
||||||
Cost *p_startup_cost,
|
Cost *p_startup_cost,
|
||||||
Cost *p_run_cost);
|
Cost *p_run_cost);
|
||||||
static bool ec_member_matches_foreign(PlannerInfo *root, RelOptInfo *rel,
|
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,
|
estimate_path_cost_size(root, baserel, NIL, NIL, NULL,
|
||||||
&fpinfo->rows, &fpinfo->width,
|
&fpinfo->rows, &fpinfo->width,
|
||||||
|
&fpinfo->disabled_nodes,
|
||||||
&fpinfo->startup_cost, &fpinfo->total_cost);
|
&fpinfo->startup_cost, &fpinfo->total_cost);
|
||||||
|
|
||||||
/* Report estimated baserel size to planner. */
|
/* Report estimated baserel size to planner. */
|
||||||
|
@ -765,6 +768,7 @@ postgresGetForeignRelSize(PlannerInfo *root,
|
||||||
/* Fill in basically-bogus cost estimates for use later. */
|
/* Fill in basically-bogus cost estimates for use later. */
|
||||||
estimate_path_cost_size(root, baserel, NIL, NIL, NULL,
|
estimate_path_cost_size(root, baserel, NIL, NIL, NULL,
|
||||||
&fpinfo->rows, &fpinfo->width,
|
&fpinfo->rows, &fpinfo->width,
|
||||||
|
&fpinfo->disabled_nodes,
|
||||||
&fpinfo->startup_cost, &fpinfo->total_cost);
|
&fpinfo->startup_cost, &fpinfo->total_cost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1030,6 +1034,7 @@ postgresGetForeignPaths(PlannerInfo *root,
|
||||||
path = create_foreignscan_path(root, baserel,
|
path = create_foreignscan_path(root, baserel,
|
||||||
NULL, /* default pathtarget */
|
NULL, /* default pathtarget */
|
||||||
fpinfo->rows,
|
fpinfo->rows,
|
||||||
|
fpinfo->disabled_nodes,
|
||||||
fpinfo->startup_cost,
|
fpinfo->startup_cost,
|
||||||
fpinfo->total_cost,
|
fpinfo->total_cost,
|
||||||
NIL, /* no pathkeys */
|
NIL, /* no pathkeys */
|
||||||
|
@ -1184,13 +1189,14 @@ postgresGetForeignPaths(PlannerInfo *root,
|
||||||
ParamPathInfo *param_info = (ParamPathInfo *) lfirst(lc);
|
ParamPathInfo *param_info = (ParamPathInfo *) lfirst(lc);
|
||||||
double rows;
|
double rows;
|
||||||
int width;
|
int width;
|
||||||
|
int disabled_nodes;
|
||||||
Cost startup_cost;
|
Cost startup_cost;
|
||||||
Cost total_cost;
|
Cost total_cost;
|
||||||
|
|
||||||
/* Get a cost estimate from the remote */
|
/* Get a cost estimate from the remote */
|
||||||
estimate_path_cost_size(root, baserel,
|
estimate_path_cost_size(root, baserel,
|
||||||
param_info->ppi_clauses, NIL, NULL,
|
param_info->ppi_clauses, NIL, NULL,
|
||||||
&rows, &width,
|
&rows, &width, &disabled_nodes,
|
||||||
&startup_cost, &total_cost);
|
&startup_cost, &total_cost);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1203,6 +1209,7 @@ postgresGetForeignPaths(PlannerInfo *root,
|
||||||
path = create_foreignscan_path(root, baserel,
|
path = create_foreignscan_path(root, baserel,
|
||||||
NULL, /* default pathtarget */
|
NULL, /* default pathtarget */
|
||||||
rows,
|
rows,
|
||||||
|
disabled_nodes,
|
||||||
startup_cost,
|
startup_cost,
|
||||||
total_cost,
|
total_cost,
|
||||||
NIL, /* no pathkeys */
|
NIL, /* no pathkeys */
|
||||||
|
@ -3079,7 +3086,7 @@ postgresExecForeignTruncate(List *rels,
|
||||||
* final sort and the LIMIT restriction.
|
* final sort and the LIMIT restriction.
|
||||||
*
|
*
|
||||||
* The function returns the cost and size estimates in p_rows, p_width,
|
* 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
|
static void
|
||||||
estimate_path_cost_size(PlannerInfo *root,
|
estimate_path_cost_size(PlannerInfo *root,
|
||||||
|
@ -3088,12 +3095,14 @@ estimate_path_cost_size(PlannerInfo *root,
|
||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
PgFdwPathExtraData *fpextra,
|
PgFdwPathExtraData *fpextra,
|
||||||
double *p_rows, int *p_width,
|
double *p_rows, int *p_width,
|
||||||
|
int *p_disabled_nodes,
|
||||||
Cost *p_startup_cost, Cost *p_total_cost)
|
Cost *p_startup_cost, Cost *p_total_cost)
|
||||||
{
|
{
|
||||||
PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
|
PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) foreignrel->fdw_private;
|
||||||
double rows;
|
double rows;
|
||||||
double retrieved_rows;
|
double retrieved_rows;
|
||||||
int width;
|
int width;
|
||||||
|
int disabled_nodes = 0;
|
||||||
Cost startup_cost;
|
Cost startup_cost;
|
||||||
Cost total_cost;
|
Cost total_cost;
|
||||||
|
|
||||||
|
@ -3483,6 +3492,7 @@ estimate_path_cost_size(PlannerInfo *root,
|
||||||
adjust_foreign_grouping_path_cost(root, pathkeys,
|
adjust_foreign_grouping_path_cost(root, pathkeys,
|
||||||
retrieved_rows, width,
|
retrieved_rows, width,
|
||||||
fpextra->limit_tuples,
|
fpextra->limit_tuples,
|
||||||
|
&disabled_nodes,
|
||||||
&startup_cost, &run_cost);
|
&startup_cost, &run_cost);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -3577,6 +3587,7 @@ estimate_path_cost_size(PlannerInfo *root,
|
||||||
/* Return results. */
|
/* Return results. */
|
||||||
*p_rows = rows;
|
*p_rows = rows;
|
||||||
*p_width = width;
|
*p_width = width;
|
||||||
|
*p_disabled_nodes = disabled_nodes;
|
||||||
*p_startup_cost = startup_cost;
|
*p_startup_cost = startup_cost;
|
||||||
*p_total_cost = total_cost;
|
*p_total_cost = total_cost;
|
||||||
}
|
}
|
||||||
|
@ -3637,6 +3648,7 @@ adjust_foreign_grouping_path_cost(PlannerInfo *root,
|
||||||
double retrieved_rows,
|
double retrieved_rows,
|
||||||
double width,
|
double width,
|
||||||
double limit_tuples,
|
double limit_tuples,
|
||||||
|
int *p_disabled_nodes,
|
||||||
Cost *p_startup_cost,
|
Cost *p_startup_cost,
|
||||||
Cost *p_run_cost)
|
Cost *p_run_cost)
|
||||||
{
|
{
|
||||||
|
@ -3656,6 +3668,7 @@ adjust_foreign_grouping_path_cost(PlannerInfo *root,
|
||||||
cost_sort(&sort_path,
|
cost_sort(&sort_path,
|
||||||
root,
|
root,
|
||||||
pathkeys,
|
pathkeys,
|
||||||
|
0,
|
||||||
*p_startup_cost + *p_run_cost,
|
*p_startup_cost + *p_run_cost,
|
||||||
retrieved_rows,
|
retrieved_rows,
|
||||||
width,
|
width,
|
||||||
|
@ -6147,13 +6160,15 @@ add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
|
||||||
{
|
{
|
||||||
double rows;
|
double rows;
|
||||||
int width;
|
int width;
|
||||||
|
int disabled_nodes;
|
||||||
Cost startup_cost;
|
Cost startup_cost;
|
||||||
Cost total_cost;
|
Cost total_cost;
|
||||||
List *useful_pathkeys = lfirst(lc);
|
List *useful_pathkeys = lfirst(lc);
|
||||||
Path *sorted_epq_path;
|
Path *sorted_epq_path;
|
||||||
|
|
||||||
estimate_path_cost_size(root, rel, NIL, useful_pathkeys, NULL,
|
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
|
* 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,
|
create_foreignscan_path(root, rel,
|
||||||
NULL,
|
NULL,
|
||||||
rows,
|
rows,
|
||||||
|
disabled_nodes,
|
||||||
startup_cost,
|
startup_cost,
|
||||||
total_cost,
|
total_cost,
|
||||||
useful_pathkeys,
|
useful_pathkeys,
|
||||||
|
@ -6188,6 +6204,7 @@ add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
|
||||||
create_foreign_join_path(root, rel,
|
create_foreign_join_path(root, rel,
|
||||||
NULL,
|
NULL,
|
||||||
rows,
|
rows,
|
||||||
|
disabled_nodes,
|
||||||
startup_cost,
|
startup_cost,
|
||||||
total_cost,
|
total_cost,
|
||||||
useful_pathkeys,
|
useful_pathkeys,
|
||||||
|
@ -6335,6 +6352,7 @@ postgresGetForeignJoinPaths(PlannerInfo *root,
|
||||||
ForeignPath *joinpath;
|
ForeignPath *joinpath;
|
||||||
double rows;
|
double rows;
|
||||||
int width;
|
int width;
|
||||||
|
int disabled_nodes;
|
||||||
Cost startup_cost;
|
Cost startup_cost;
|
||||||
Cost total_cost;
|
Cost total_cost;
|
||||||
Path *epq_path; /* Path to create plan to be executed when
|
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 costs for bare join relation */
|
||||||
estimate_path_cost_size(root, joinrel, NIL, NIL, NULL,
|
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 */
|
/* Now update this information in the joinrel */
|
||||||
joinrel->rows = rows;
|
joinrel->rows = rows;
|
||||||
joinrel->reltarget->width = width;
|
joinrel->reltarget->width = width;
|
||||||
fpinfo->rows = rows;
|
fpinfo->rows = rows;
|
||||||
fpinfo->width = width;
|
fpinfo->width = width;
|
||||||
|
fpinfo->disabled_nodes = disabled_nodes;
|
||||||
fpinfo->startup_cost = startup_cost;
|
fpinfo->startup_cost = startup_cost;
|
||||||
fpinfo->total_cost = total_cost;
|
fpinfo->total_cost = total_cost;
|
||||||
|
|
||||||
|
@ -6441,6 +6461,7 @@ postgresGetForeignJoinPaths(PlannerInfo *root,
|
||||||
joinrel,
|
joinrel,
|
||||||
NULL, /* default pathtarget */
|
NULL, /* default pathtarget */
|
||||||
rows,
|
rows,
|
||||||
|
disabled_nodes,
|
||||||
startup_cost,
|
startup_cost,
|
||||||
total_cost,
|
total_cost,
|
||||||
NIL, /* no pathkeys */
|
NIL, /* no pathkeys */
|
||||||
|
@ -6768,6 +6789,7 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||||
ForeignPath *grouppath;
|
ForeignPath *grouppath;
|
||||||
double rows;
|
double rows;
|
||||||
int width;
|
int width;
|
||||||
|
int disabled_nodes;
|
||||||
Cost startup_cost;
|
Cost startup_cost;
|
||||||
Cost total_cost;
|
Cost total_cost;
|
||||||
|
|
||||||
|
@ -6818,11 +6840,13 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||||
|
|
||||||
/* Estimate the cost of push down */
|
/* Estimate the cost of push down */
|
||||||
estimate_path_cost_size(root, grouped_rel, NIL, NIL, NULL,
|
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 */
|
/* Now update this information in the fpinfo */
|
||||||
fpinfo->rows = rows;
|
fpinfo->rows = rows;
|
||||||
fpinfo->width = width;
|
fpinfo->width = width;
|
||||||
|
fpinfo->disabled_nodes = disabled_nodes;
|
||||||
fpinfo->startup_cost = startup_cost;
|
fpinfo->startup_cost = startup_cost;
|
||||||
fpinfo->total_cost = total_cost;
|
fpinfo->total_cost = total_cost;
|
||||||
|
|
||||||
|
@ -6831,6 +6855,7 @@ add_foreign_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||||
grouped_rel,
|
grouped_rel,
|
||||||
grouped_rel->reltarget,
|
grouped_rel->reltarget,
|
||||||
rows,
|
rows,
|
||||||
|
disabled_nodes,
|
||||||
startup_cost,
|
startup_cost,
|
||||||
total_cost,
|
total_cost,
|
||||||
NIL, /* no pathkeys */
|
NIL, /* no pathkeys */
|
||||||
|
@ -6859,6 +6884,7 @@ add_foreign_ordered_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||||
PgFdwPathExtraData *fpextra;
|
PgFdwPathExtraData *fpextra;
|
||||||
double rows;
|
double rows;
|
||||||
int width;
|
int width;
|
||||||
|
int disabled_nodes;
|
||||||
Cost startup_cost;
|
Cost startup_cost;
|
||||||
Cost total_cost;
|
Cost total_cost;
|
||||||
List *fdw_private;
|
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 the costs of performing the final sort remotely */
|
||||||
estimate_path_cost_size(root, input_rel, NIL, root->sort_pathkeys, fpextra,
|
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.
|
* 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,
|
input_rel,
|
||||||
root->upper_targets[UPPERREL_ORDERED],
|
root->upper_targets[UPPERREL_ORDERED],
|
||||||
rows,
|
rows,
|
||||||
|
disabled_nodes,
|
||||||
startup_cost,
|
startup_cost,
|
||||||
total_cost,
|
total_cost,
|
||||||
root->sort_pathkeys,
|
root->sort_pathkeys,
|
||||||
|
@ -6998,6 +7026,7 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||||
bool save_use_remote_estimate = false;
|
bool save_use_remote_estimate = false;
|
||||||
double rows;
|
double rows;
|
||||||
int width;
|
int width;
|
||||||
|
int disabled_nodes;
|
||||||
Cost startup_cost;
|
Cost startup_cost;
|
||||||
Cost total_cost;
|
Cost total_cost;
|
||||||
List *fdw_private;
|
List *fdw_private;
|
||||||
|
@ -7082,6 +7111,7 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||||
path->parent,
|
path->parent,
|
||||||
path->pathtarget,
|
path->pathtarget,
|
||||||
path->rows,
|
path->rows,
|
||||||
|
path->disabled_nodes,
|
||||||
path->startup_cost,
|
path->startup_cost,
|
||||||
path->total_cost,
|
path->total_cost,
|
||||||
path->pathkeys,
|
path->pathkeys,
|
||||||
|
@ -7199,7 +7229,8 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||||
ifpinfo->use_remote_estimate = false;
|
ifpinfo->use_remote_estimate = false;
|
||||||
}
|
}
|
||||||
estimate_path_cost_size(root, input_rel, NIL, pathkeys, fpextra,
|
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)
|
if (!fpextra->has_final_sort)
|
||||||
ifpinfo->use_remote_estimate = save_use_remote_estimate;
|
ifpinfo->use_remote_estimate = save_use_remote_estimate;
|
||||||
|
|
||||||
|
@ -7218,6 +7249,7 @@ add_foreign_final_paths(PlannerInfo *root, RelOptInfo *input_rel,
|
||||||
input_rel,
|
input_rel,
|
||||||
root->upper_targets[UPPERREL_FINAL],
|
root->upper_targets[UPPERREL_FINAL],
|
||||||
rows,
|
rows,
|
||||||
|
disabled_nodes,
|
||||||
startup_cost,
|
startup_cost,
|
||||||
total_cost,
|
total_cost,
|
||||||
pathkeys,
|
pathkeys,
|
||||||
|
|
|
@ -62,6 +62,7 @@ typedef struct PgFdwRelationInfo
|
||||||
/* Estimated size and cost for a scan, join, or grouping/aggregation. */
|
/* Estimated size and cost for a scan, join, or grouping/aggregation. */
|
||||||
double rows;
|
double rows;
|
||||||
int width;
|
int width;
|
||||||
|
int disabled_nodes;
|
||||||
Cost startup_cost;
|
Cost startup_cost;
|
||||||
Cost total_cost;
|
Cost total_cost;
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,17 @@
|
||||||
* so beware of division-by-zero.) The LIMIT is applied as a top-level
|
* so beware of division-by-zero.) The LIMIT is applied as a top-level
|
||||||
* plan node.
|
* plan node.
|
||||||
*
|
*
|
||||||
|
* Each path stores the total number of disabled nodes that exist at or
|
||||||
|
* below that point in the plan tree. This is regarded as a component of
|
||||||
|
* the cost, and paths with fewer disabled nodes should be regarded as
|
||||||
|
* cheaper than those with more. Disabled nodes occur when the user sets
|
||||||
|
* a GUC like enable_seqscan=false. We can't necessarily respect such a
|
||||||
|
* setting in every part of the plan tree, but we want to respect in as many
|
||||||
|
* parts of the plan tree as possible. Simpler schemes like storing a Boolean
|
||||||
|
* here rather than a count fail to do that. We used to disable nodes by
|
||||||
|
* adding a large constant to the startup cost, but that distorted planning
|
||||||
|
* in other ways.
|
||||||
|
*
|
||||||
* For largely historical reasons, most of the routines in this module use
|
* For largely historical reasons, most of the routines in this module use
|
||||||
* the passed result Path only to store their results (rows, startup_cost and
|
* the passed result Path only to store their results (rows, startup_cost and
|
||||||
* total_cost) into. All the input data they need is passed as separate
|
* total_cost) into. All the input data they need is passed as separate
|
||||||
|
@ -301,9 +312,6 @@ cost_seqscan(Path *path, PlannerInfo *root,
|
||||||
else
|
else
|
||||||
path->rows = baserel->rows;
|
path->rows = baserel->rows;
|
||||||
|
|
||||||
if (!enable_seqscan)
|
|
||||||
startup_cost += disable_cost;
|
|
||||||
|
|
||||||
/* fetch estimated page cost for tablespace containing table */
|
/* fetch estimated page cost for tablespace containing table */
|
||||||
get_tablespace_page_costs(baserel->reltablespace,
|
get_tablespace_page_costs(baserel->reltablespace,
|
||||||
NULL,
|
NULL,
|
||||||
|
@ -346,6 +354,7 @@ cost_seqscan(Path *path, PlannerInfo *root,
|
||||||
path->rows = clamp_row_est(path->rows / parallel_divisor);
|
path->rows = clamp_row_est(path->rows / parallel_divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
path->disabled_nodes = enable_seqscan ? 0 : 1;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + cpu_run_cost + disk_run_cost;
|
path->total_cost = startup_cost + cpu_run_cost + disk_run_cost;
|
||||||
}
|
}
|
||||||
|
@ -418,6 +427,7 @@ cost_samplescan(Path *path, PlannerInfo *root,
|
||||||
startup_cost += path->pathtarget->cost.startup;
|
startup_cost += path->pathtarget->cost.startup;
|
||||||
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
||||||
|
|
||||||
|
path->disabled_nodes = 0;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -456,6 +466,7 @@ cost_gather(GatherPath *path, PlannerInfo *root,
|
||||||
startup_cost += parallel_setup_cost;
|
startup_cost += parallel_setup_cost;
|
||||||
run_cost += parallel_tuple_cost * path->path.rows;
|
run_cost += parallel_tuple_cost * path->path.rows;
|
||||||
|
|
||||||
|
path->path.disabled_nodes = path->subpath->disabled_nodes;
|
||||||
path->path.startup_cost = startup_cost;
|
path->path.startup_cost = startup_cost;
|
||||||
path->path.total_cost = (startup_cost + run_cost);
|
path->path.total_cost = (startup_cost + run_cost);
|
||||||
}
|
}
|
||||||
|
@ -473,6 +484,7 @@ cost_gather(GatherPath *path, PlannerInfo *root,
|
||||||
void
|
void
|
||||||
cost_gather_merge(GatherMergePath *path, PlannerInfo *root,
|
cost_gather_merge(GatherMergePath *path, PlannerInfo *root,
|
||||||
RelOptInfo *rel, ParamPathInfo *param_info,
|
RelOptInfo *rel, ParamPathInfo *param_info,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double *rows)
|
double *rows)
|
||||||
{
|
{
|
||||||
|
@ -490,9 +502,6 @@ cost_gather_merge(GatherMergePath *path, PlannerInfo *root,
|
||||||
else
|
else
|
||||||
path->path.rows = rel->rows;
|
path->path.rows = rel->rows;
|
||||||
|
|
||||||
if (!enable_gathermerge)
|
|
||||||
startup_cost += disable_cost;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add one to the number of workers to account for the leader. This might
|
* Add one to the number of workers to account for the leader. This might
|
||||||
* be overgenerous since the leader will do less work than other workers
|
* be overgenerous since the leader will do less work than other workers
|
||||||
|
@ -523,6 +532,8 @@ cost_gather_merge(GatherMergePath *path, PlannerInfo *root,
|
||||||
startup_cost += parallel_setup_cost;
|
startup_cost += parallel_setup_cost;
|
||||||
run_cost += parallel_tuple_cost * path->path.rows * 1.05;
|
run_cost += parallel_tuple_cost * path->path.rows * 1.05;
|
||||||
|
|
||||||
|
path->path.disabled_nodes = input_disabled_nodes
|
||||||
|
+ (enable_gathermerge ? 0 : 1);
|
||||||
path->path.startup_cost = startup_cost + input_startup_cost;
|
path->path.startup_cost = startup_cost + input_startup_cost;
|
||||||
path->path.total_cost = (startup_cost + run_cost + input_total_cost);
|
path->path.total_cost = (startup_cost + run_cost + input_total_cost);
|
||||||
}
|
}
|
||||||
|
@ -603,9 +614,8 @@ cost_index(IndexPath *path, PlannerInfo *root, double loop_count,
|
||||||
path->indexclauses);
|
path->indexclauses);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!enable_indexscan)
|
|
||||||
startup_cost += disable_cost;
|
|
||||||
/* we don't need to check enable_indexonlyscan; indxpath.c does that */
|
/* we don't need to check enable_indexonlyscan; indxpath.c does that */
|
||||||
|
path->path.disabled_nodes = enable_indexscan ? 0 : 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call index-access-method-specific code to estimate the processing cost
|
* Call index-access-method-specific code to estimate the processing cost
|
||||||
|
@ -1038,9 +1048,6 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
|
||||||
else
|
else
|
||||||
path->rows = baserel->rows;
|
path->rows = baserel->rows;
|
||||||
|
|
||||||
if (!enable_bitmapscan)
|
|
||||||
startup_cost += disable_cost;
|
|
||||||
|
|
||||||
pages_fetched = compute_bitmap_pages(root, baserel, bitmapqual,
|
pages_fetched = compute_bitmap_pages(root, baserel, bitmapqual,
|
||||||
loop_count, &indexTotalCost,
|
loop_count, &indexTotalCost,
|
||||||
&tuples_fetched);
|
&tuples_fetched);
|
||||||
|
@ -1102,6 +1109,7 @@ cost_bitmap_heap_scan(Path *path, PlannerInfo *root, RelOptInfo *baserel,
|
||||||
startup_cost += path->pathtarget->cost.startup;
|
startup_cost += path->pathtarget->cost.startup;
|
||||||
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
||||||
|
|
||||||
|
path->disabled_nodes = enable_bitmapscan ? 0 : 1;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -1187,6 +1195,7 @@ cost_bitmap_and_node(BitmapAndPath *path, PlannerInfo *root)
|
||||||
}
|
}
|
||||||
path->bitmapselectivity = selec;
|
path->bitmapselectivity = selec;
|
||||||
path->path.rows = 0; /* per above, not used */
|
path->path.rows = 0; /* per above, not used */
|
||||||
|
path->path.disabled_nodes = 0;
|
||||||
path->path.startup_cost = totalCost;
|
path->path.startup_cost = totalCost;
|
||||||
path->path.total_cost = totalCost;
|
path->path.total_cost = totalCost;
|
||||||
}
|
}
|
||||||
|
@ -1261,6 +1270,7 @@ cost_tidscan(Path *path, PlannerInfo *root,
|
||||||
/* Should only be applied to base relations */
|
/* Should only be applied to base relations */
|
||||||
Assert(baserel->relid > 0);
|
Assert(baserel->relid > 0);
|
||||||
Assert(baserel->rtekind == RTE_RELATION);
|
Assert(baserel->rtekind == RTE_RELATION);
|
||||||
|
Assert(tidquals != NIL);
|
||||||
|
|
||||||
/* Mark the path with the correct row estimate */
|
/* Mark the path with the correct row estimate */
|
||||||
if (param_info)
|
if (param_info)
|
||||||
|
@ -1275,6 +1285,14 @@ cost_tidscan(Path *path, PlannerInfo *root,
|
||||||
RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
|
RestrictInfo *rinfo = lfirst_node(RestrictInfo, l);
|
||||||
Expr *qual = rinfo->clause;
|
Expr *qual = rinfo->clause;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must use a TID scan for CurrentOfExpr; in any other case, we
|
||||||
|
* should be generating a TID scan only if enable_tidscan=true. Also,
|
||||||
|
* if CurrentOfExpr is the qual, there should be only one.
|
||||||
|
*/
|
||||||
|
Assert(enable_tidscan || IsA(qual, CurrentOfExpr));
|
||||||
|
Assert(list_length(tidquals) == 1 || !IsA(qual, CurrentOfExpr));
|
||||||
|
|
||||||
if (IsA(qual, ScalarArrayOpExpr))
|
if (IsA(qual, ScalarArrayOpExpr))
|
||||||
{
|
{
|
||||||
/* Each element of the array yields 1 tuple */
|
/* Each element of the array yields 1 tuple */
|
||||||
|
@ -1322,6 +1340,12 @@ cost_tidscan(Path *path, PlannerInfo *root,
|
||||||
startup_cost += path->pathtarget->cost.startup;
|
startup_cost += path->pathtarget->cost.startup;
|
||||||
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* There are assertions above verifying that we only reach this function
|
||||||
|
* either when enable_tidscan=true or when the TID scan is the only legal
|
||||||
|
* path, so it's safe to set disabled_nodes to zero here.
|
||||||
|
*/
|
||||||
|
path->disabled_nodes = 0;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -1414,6 +1438,9 @@ cost_tidrangescan(Path *path, PlannerInfo *root,
|
||||||
startup_cost += path->pathtarget->cost.startup;
|
startup_cost += path->pathtarget->cost.startup;
|
||||||
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
||||||
|
|
||||||
|
/* we should not generate this path type when enable_tidscan=false */
|
||||||
|
Assert(enable_tidscan);
|
||||||
|
path->disabled_nodes = 0;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -1466,6 +1493,7 @@ cost_subqueryscan(SubqueryScanPath *path, PlannerInfo *root,
|
||||||
* SubqueryScan node, plus cpu_tuple_cost to account for selection and
|
* SubqueryScan node, plus cpu_tuple_cost to account for selection and
|
||||||
* projection overhead.
|
* projection overhead.
|
||||||
*/
|
*/
|
||||||
|
path->path.disabled_nodes = path->subpath->disabled_nodes;
|
||||||
path->path.startup_cost = path->subpath->startup_cost;
|
path->path.startup_cost = path->subpath->startup_cost;
|
||||||
path->path.total_cost = path->subpath->total_cost;
|
path->path.total_cost = path->subpath->total_cost;
|
||||||
|
|
||||||
|
@ -1556,6 +1584,7 @@ cost_functionscan(Path *path, PlannerInfo *root,
|
||||||
startup_cost += path->pathtarget->cost.startup;
|
startup_cost += path->pathtarget->cost.startup;
|
||||||
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
||||||
|
|
||||||
|
path->disabled_nodes = 0;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -1612,6 +1641,7 @@ cost_tablefuncscan(Path *path, PlannerInfo *root,
|
||||||
startup_cost += path->pathtarget->cost.startup;
|
startup_cost += path->pathtarget->cost.startup;
|
||||||
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
||||||
|
|
||||||
|
path->disabled_nodes = 0;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -1659,6 +1689,7 @@ cost_valuesscan(Path *path, PlannerInfo *root,
|
||||||
startup_cost += path->pathtarget->cost.startup;
|
startup_cost += path->pathtarget->cost.startup;
|
||||||
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
||||||
|
|
||||||
|
path->disabled_nodes = 0;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -1706,6 +1737,7 @@ cost_ctescan(Path *path, PlannerInfo *root,
|
||||||
startup_cost += path->pathtarget->cost.startup;
|
startup_cost += path->pathtarget->cost.startup;
|
||||||
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
run_cost += path->pathtarget->cost.per_tuple * path->rows;
|
||||||
|
|
||||||
|
path->disabled_nodes = 0;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -1743,6 +1775,7 @@ cost_namedtuplestorescan(Path *path, PlannerInfo *root,
|
||||||
cpu_per_tuple += cpu_tuple_cost + qpqual_cost.per_tuple;
|
cpu_per_tuple += cpu_tuple_cost + qpqual_cost.per_tuple;
|
||||||
run_cost += cpu_per_tuple * baserel->tuples;
|
run_cost += cpu_per_tuple * baserel->tuples;
|
||||||
|
|
||||||
|
path->disabled_nodes = 0;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -1777,6 +1810,7 @@ cost_resultscan(Path *path, PlannerInfo *root,
|
||||||
cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple;
|
cpu_per_tuple = cpu_tuple_cost + qpqual_cost.per_tuple;
|
||||||
run_cost += cpu_per_tuple * baserel->tuples;
|
run_cost += cpu_per_tuple * baserel->tuples;
|
||||||
|
|
||||||
|
path->disabled_nodes = 0;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -1816,6 +1850,7 @@ cost_recursive_union(Path *runion, Path *nrterm, Path *rterm)
|
||||||
*/
|
*/
|
||||||
total_cost += cpu_tuple_cost * total_rows;
|
total_cost += cpu_tuple_cost * total_rows;
|
||||||
|
|
||||||
|
runion->disabled_nodes = nrterm->disabled_nodes + rterm->disabled_nodes;
|
||||||
runion->startup_cost = startup_cost;
|
runion->startup_cost = startup_cost;
|
||||||
runion->total_cost = total_cost;
|
runion->total_cost = total_cost;
|
||||||
runion->rows = total_rows;
|
runion->rows = total_rows;
|
||||||
|
@ -1964,6 +1999,7 @@ cost_tuplesort(Cost *startup_cost, Cost *run_cost,
|
||||||
void
|
void
|
||||||
cost_incremental_sort(Path *path,
|
cost_incremental_sort(Path *path,
|
||||||
PlannerInfo *root, List *pathkeys, int presorted_keys,
|
PlannerInfo *root, List *pathkeys, int presorted_keys,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double input_tuples, int width, Cost comparison_cost, int sort_mem,
|
double input_tuples, int width, Cost comparison_cost, int sort_mem,
|
||||||
double limit_tuples)
|
double limit_tuples)
|
||||||
|
@ -2083,6 +2119,11 @@ cost_incremental_sort(Path *path,
|
||||||
run_cost += 2.0 * cpu_tuple_cost * input_groups;
|
run_cost += 2.0 * cpu_tuple_cost * input_groups;
|
||||||
|
|
||||||
path->rows = input_tuples;
|
path->rows = input_tuples;
|
||||||
|
|
||||||
|
/* should not generate these paths when enable_incremental_sort=false */
|
||||||
|
Assert(enable_incremental_sort);
|
||||||
|
path->disabled_nodes = input_disabled_nodes;
|
||||||
|
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -2101,7 +2142,8 @@ cost_incremental_sort(Path *path,
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
cost_sort(Path *path, PlannerInfo *root,
|
cost_sort(Path *path, PlannerInfo *root,
|
||||||
List *pathkeys, Cost input_cost, double tuples, int width,
|
List *pathkeys, int input_disabled_nodes,
|
||||||
|
Cost input_cost, double tuples, int width,
|
||||||
Cost comparison_cost, int sort_mem,
|
Cost comparison_cost, int sort_mem,
|
||||||
double limit_tuples)
|
double limit_tuples)
|
||||||
|
|
||||||
|
@ -2114,12 +2156,10 @@ cost_sort(Path *path, PlannerInfo *root,
|
||||||
comparison_cost, sort_mem,
|
comparison_cost, sort_mem,
|
||||||
limit_tuples);
|
limit_tuples);
|
||||||
|
|
||||||
if (!enable_sort)
|
|
||||||
startup_cost += disable_cost;
|
|
||||||
|
|
||||||
startup_cost += input_cost;
|
startup_cost += input_cost;
|
||||||
|
|
||||||
path->rows = tuples;
|
path->rows = tuples;
|
||||||
|
path->disabled_nodes = input_disabled_nodes + (enable_sort ? 0 : 1);
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -2211,6 +2251,7 @@ cost_append(AppendPath *apath)
|
||||||
{
|
{
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
|
apath->path.disabled_nodes = 0;
|
||||||
apath->path.startup_cost = 0;
|
apath->path.startup_cost = 0;
|
||||||
apath->path.total_cost = 0;
|
apath->path.total_cost = 0;
|
||||||
apath->path.rows = 0;
|
apath->path.rows = 0;
|
||||||
|
@ -2232,12 +2273,16 @@ cost_append(AppendPath *apath)
|
||||||
*/
|
*/
|
||||||
apath->path.startup_cost = firstsubpath->startup_cost;
|
apath->path.startup_cost = firstsubpath->startup_cost;
|
||||||
|
|
||||||
/* Compute rows and costs as sums of subplan rows and costs. */
|
/*
|
||||||
|
* Compute rows, number of disabled nodes, and total cost as sums
|
||||||
|
* of underlying subplan values.
|
||||||
|
*/
|
||||||
foreach(l, apath->subpaths)
|
foreach(l, apath->subpaths)
|
||||||
{
|
{
|
||||||
Path *subpath = (Path *) lfirst(l);
|
Path *subpath = (Path *) lfirst(l);
|
||||||
|
|
||||||
apath->path.rows += subpath->rows;
|
apath->path.rows += subpath->rows;
|
||||||
|
apath->path.disabled_nodes += subpath->disabled_nodes;
|
||||||
apath->path.total_cost += subpath->total_cost;
|
apath->path.total_cost += subpath->total_cost;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2277,6 +2322,7 @@ cost_append(AppendPath *apath)
|
||||||
cost_sort(&sort_path,
|
cost_sort(&sort_path,
|
||||||
NULL, /* doesn't currently need root */
|
NULL, /* doesn't currently need root */
|
||||||
pathkeys,
|
pathkeys,
|
||||||
|
subpath->disabled_nodes,
|
||||||
subpath->total_cost,
|
subpath->total_cost,
|
||||||
subpath->rows,
|
subpath->rows,
|
||||||
subpath->pathtarget->width,
|
subpath->pathtarget->width,
|
||||||
|
@ -2287,6 +2333,7 @@ cost_append(AppendPath *apath)
|
||||||
}
|
}
|
||||||
|
|
||||||
apath->path.rows += subpath->rows;
|
apath->path.rows += subpath->rows;
|
||||||
|
apath->path.disabled_nodes += subpath->disabled_nodes;
|
||||||
apath->path.startup_cost += subpath->startup_cost;
|
apath->path.startup_cost += subpath->startup_cost;
|
||||||
apath->path.total_cost += subpath->total_cost;
|
apath->path.total_cost += subpath->total_cost;
|
||||||
}
|
}
|
||||||
|
@ -2335,6 +2382,7 @@ cost_append(AppendPath *apath)
|
||||||
apath->path.total_cost += subpath->total_cost;
|
apath->path.total_cost += subpath->total_cost;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
apath->path.disabled_nodes += subpath->disabled_nodes;
|
||||||
apath->path.rows = clamp_row_est(apath->path.rows);
|
apath->path.rows = clamp_row_est(apath->path.rows);
|
||||||
|
|
||||||
i++;
|
i++;
|
||||||
|
@ -2375,6 +2423,7 @@ cost_append(AppendPath *apath)
|
||||||
*
|
*
|
||||||
* 'pathkeys' is a list of sort keys
|
* 'pathkeys' is a list of sort keys
|
||||||
* 'n_streams' is the number of input streams
|
* 'n_streams' is the number of input streams
|
||||||
|
* 'input_disabled_nodes' is the sum of the input streams' disabled node counts
|
||||||
* 'input_startup_cost' is the sum of the input streams' startup costs
|
* 'input_startup_cost' is the sum of the input streams' startup costs
|
||||||
* 'input_total_cost' is the sum of the input streams' total costs
|
* 'input_total_cost' is the sum of the input streams' total costs
|
||||||
* 'tuples' is the number of tuples in all the streams
|
* 'tuples' is the number of tuples in all the streams
|
||||||
|
@ -2382,6 +2431,7 @@ cost_append(AppendPath *apath)
|
||||||
void
|
void
|
||||||
cost_merge_append(Path *path, PlannerInfo *root,
|
cost_merge_append(Path *path, PlannerInfo *root,
|
||||||
List *pathkeys, int n_streams,
|
List *pathkeys, int n_streams,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double tuples)
|
double tuples)
|
||||||
{
|
{
|
||||||
|
@ -2412,6 +2462,7 @@ cost_merge_append(Path *path, PlannerInfo *root,
|
||||||
*/
|
*/
|
||||||
run_cost += cpu_tuple_cost * APPEND_CPU_COST_MULTIPLIER * tuples;
|
run_cost += cpu_tuple_cost * APPEND_CPU_COST_MULTIPLIER * tuples;
|
||||||
|
|
||||||
|
path->disabled_nodes = input_disabled_nodes;
|
||||||
path->startup_cost = startup_cost + input_startup_cost;
|
path->startup_cost = startup_cost + input_startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost + input_total_cost;
|
path->total_cost = startup_cost + run_cost + input_total_cost;
|
||||||
}
|
}
|
||||||
|
@ -2430,6 +2481,7 @@ cost_merge_append(Path *path, PlannerInfo *root,
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
cost_material(Path *path,
|
cost_material(Path *path,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double tuples, int width)
|
double tuples, int width)
|
||||||
{
|
{
|
||||||
|
@ -2467,6 +2519,7 @@ cost_material(Path *path,
|
||||||
run_cost += seq_page_cost * npages;
|
run_cost += seq_page_cost * npages;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
path->disabled_nodes = input_disabled_nodes + (enable_material ? 0 : 1);
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = startup_cost + run_cost;
|
path->total_cost = startup_cost + run_cost;
|
||||||
}
|
}
|
||||||
|
@ -2630,6 +2683,7 @@ cost_agg(Path *path, PlannerInfo *root,
|
||||||
AggStrategy aggstrategy, const AggClauseCosts *aggcosts,
|
AggStrategy aggstrategy, const AggClauseCosts *aggcosts,
|
||||||
int numGroupCols, double numGroups,
|
int numGroupCols, double numGroups,
|
||||||
List *quals,
|
List *quals,
|
||||||
|
int disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double input_tuples, double input_width)
|
double input_tuples, double input_width)
|
||||||
{
|
{
|
||||||
|
@ -2685,10 +2739,7 @@ cost_agg(Path *path, PlannerInfo *root,
|
||||||
startup_cost = input_startup_cost;
|
startup_cost = input_startup_cost;
|
||||||
total_cost = input_total_cost;
|
total_cost = input_total_cost;
|
||||||
if (aggstrategy == AGG_MIXED && !enable_hashagg)
|
if (aggstrategy == AGG_MIXED && !enable_hashagg)
|
||||||
{
|
++disabled_nodes;
|
||||||
startup_cost += disable_cost;
|
|
||||||
total_cost += disable_cost;
|
|
||||||
}
|
|
||||||
/* calcs phrased this way to match HASHED case, see note above */
|
/* calcs phrased this way to match HASHED case, see note above */
|
||||||
total_cost += aggcosts->transCost.startup;
|
total_cost += aggcosts->transCost.startup;
|
||||||
total_cost += aggcosts->transCost.per_tuple * input_tuples;
|
total_cost += aggcosts->transCost.per_tuple * input_tuples;
|
||||||
|
@ -2703,7 +2754,7 @@ cost_agg(Path *path, PlannerInfo *root,
|
||||||
/* must be AGG_HASHED */
|
/* must be AGG_HASHED */
|
||||||
startup_cost = input_total_cost;
|
startup_cost = input_total_cost;
|
||||||
if (!enable_hashagg)
|
if (!enable_hashagg)
|
||||||
startup_cost += disable_cost;
|
++disabled_nodes;
|
||||||
startup_cost += aggcosts->transCost.startup;
|
startup_cost += aggcosts->transCost.startup;
|
||||||
startup_cost += aggcosts->transCost.per_tuple * input_tuples;
|
startup_cost += aggcosts->transCost.per_tuple * input_tuples;
|
||||||
/* cost of computing hash value */
|
/* cost of computing hash value */
|
||||||
|
@ -2812,6 +2863,7 @@ cost_agg(Path *path, PlannerInfo *root,
|
||||||
}
|
}
|
||||||
|
|
||||||
path->rows = output_tuples;
|
path->rows = output_tuples;
|
||||||
|
path->disabled_nodes = disabled_nodes;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = total_cost;
|
path->total_cost = total_cost;
|
||||||
}
|
}
|
||||||
|
@ -3046,6 +3098,7 @@ get_windowclause_startup_tuples(PlannerInfo *root, WindowClause *wc,
|
||||||
void
|
void
|
||||||
cost_windowagg(Path *path, PlannerInfo *root,
|
cost_windowagg(Path *path, PlannerInfo *root,
|
||||||
List *windowFuncs, WindowClause *winclause,
|
List *windowFuncs, WindowClause *winclause,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double input_tuples)
|
double input_tuples)
|
||||||
{
|
{
|
||||||
|
@ -3111,6 +3164,7 @@ cost_windowagg(Path *path, PlannerInfo *root,
|
||||||
total_cost += cpu_tuple_cost * input_tuples;
|
total_cost += cpu_tuple_cost * input_tuples;
|
||||||
|
|
||||||
path->rows = input_tuples;
|
path->rows = input_tuples;
|
||||||
|
path->disabled_nodes = input_disabled_nodes;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = total_cost;
|
path->total_cost = total_cost;
|
||||||
|
|
||||||
|
@ -3142,6 +3196,7 @@ void
|
||||||
cost_group(Path *path, PlannerInfo *root,
|
cost_group(Path *path, PlannerInfo *root,
|
||||||
int numGroupCols, double numGroups,
|
int numGroupCols, double numGroups,
|
||||||
List *quals,
|
List *quals,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double input_tuples)
|
double input_tuples)
|
||||||
{
|
{
|
||||||
|
@ -3180,6 +3235,7 @@ cost_group(Path *path, PlannerInfo *root,
|
||||||
}
|
}
|
||||||
|
|
||||||
path->rows = output_tuples;
|
path->rows = output_tuples;
|
||||||
|
path->disabled_nodes = input_disabled_nodes;
|
||||||
path->startup_cost = startup_cost;
|
path->startup_cost = startup_cost;
|
||||||
path->total_cost = total_cost;
|
path->total_cost = total_cost;
|
||||||
}
|
}
|
||||||
|
@ -3214,6 +3270,7 @@ initial_cost_nestloop(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
Path *outer_path, Path *inner_path,
|
Path *outer_path, Path *inner_path,
|
||||||
JoinPathExtraData *extra)
|
JoinPathExtraData *extra)
|
||||||
{
|
{
|
||||||
|
int disabled_nodes;
|
||||||
Cost startup_cost = 0;
|
Cost startup_cost = 0;
|
||||||
Cost run_cost = 0;
|
Cost run_cost = 0;
|
||||||
double outer_path_rows = outer_path->rows;
|
double outer_path_rows = outer_path->rows;
|
||||||
|
@ -3222,6 +3279,11 @@ initial_cost_nestloop(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
Cost inner_run_cost;
|
Cost inner_run_cost;
|
||||||
Cost inner_rescan_run_cost;
|
Cost inner_rescan_run_cost;
|
||||||
|
|
||||||
|
/* Count up disabled nodes. */
|
||||||
|
disabled_nodes = enable_nestloop ? 0 : 1;
|
||||||
|
disabled_nodes += inner_path->disabled_nodes;
|
||||||
|
disabled_nodes += outer_path->disabled_nodes;
|
||||||
|
|
||||||
/* estimate costs to rescan the inner relation */
|
/* estimate costs to rescan the inner relation */
|
||||||
cost_rescan(root, inner_path,
|
cost_rescan(root, inner_path,
|
||||||
&inner_rescan_start_cost,
|
&inner_rescan_start_cost,
|
||||||
|
@ -3269,6 +3331,7 @@ initial_cost_nestloop(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
/* CPU costs left for later */
|
/* CPU costs left for later */
|
||||||
|
|
||||||
/* Public result fields */
|
/* Public result fields */
|
||||||
|
workspace->disabled_nodes = disabled_nodes;
|
||||||
workspace->startup_cost = startup_cost;
|
workspace->startup_cost = startup_cost;
|
||||||
workspace->total_cost = startup_cost + run_cost;
|
workspace->total_cost = startup_cost + run_cost;
|
||||||
/* Save private data for final_cost_nestloop */
|
/* Save private data for final_cost_nestloop */
|
||||||
|
@ -3298,6 +3361,9 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
|
||||||
QualCost restrict_qual_cost;
|
QualCost restrict_qual_cost;
|
||||||
double ntuples;
|
double ntuples;
|
||||||
|
|
||||||
|
/* Set the number of disabled nodes. */
|
||||||
|
path->jpath.path.disabled_nodes = workspace->disabled_nodes;
|
||||||
|
|
||||||
/* Protect some assumptions below that rowcounts aren't zero */
|
/* Protect some assumptions below that rowcounts aren't zero */
|
||||||
if (outer_path_rows <= 0)
|
if (outer_path_rows <= 0)
|
||||||
outer_path_rows = 1;
|
outer_path_rows = 1;
|
||||||
|
@ -3318,14 +3384,6 @@ final_cost_nestloop(PlannerInfo *root, NestPath *path,
|
||||||
clamp_row_est(path->jpath.path.rows / parallel_divisor);
|
clamp_row_est(path->jpath.path.rows / parallel_divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We could include disable_cost in the preliminary estimate, but that
|
|
||||||
* would amount to optimizing for the case where the join method is
|
|
||||||
* disabled, which doesn't seem like the way to bet.
|
|
||||||
*/
|
|
||||||
if (!enable_nestloop)
|
|
||||||
startup_cost += disable_cost;
|
|
||||||
|
|
||||||
/* cost of inner-relation source data (we already dealt with outer rel) */
|
/* cost of inner-relation source data (we already dealt with outer rel) */
|
||||||
|
|
||||||
if (path->jpath.jointype == JOIN_SEMI || path->jpath.jointype == JOIN_ANTI ||
|
if (path->jpath.jointype == JOIN_SEMI || path->jpath.jointype == JOIN_ANTI ||
|
||||||
|
@ -3497,6 +3555,7 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
List *outersortkeys, List *innersortkeys,
|
List *outersortkeys, List *innersortkeys,
|
||||||
JoinPathExtraData *extra)
|
JoinPathExtraData *extra)
|
||||||
{
|
{
|
||||||
|
int disabled_nodes;
|
||||||
Cost startup_cost = 0;
|
Cost startup_cost = 0;
|
||||||
Cost run_cost = 0;
|
Cost run_cost = 0;
|
||||||
double outer_path_rows = outer_path->rows;
|
double outer_path_rows = outer_path->rows;
|
||||||
|
@ -3617,6 +3676,8 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
Assert(outerstartsel <= outerendsel);
|
Assert(outerstartsel <= outerendsel);
|
||||||
Assert(innerstartsel <= innerendsel);
|
Assert(innerstartsel <= innerendsel);
|
||||||
|
|
||||||
|
disabled_nodes = enable_mergejoin ? 0 : 1;
|
||||||
|
|
||||||
/* cost of source data */
|
/* cost of source data */
|
||||||
|
|
||||||
if (outersortkeys) /* do we need to sort outer? */
|
if (outersortkeys) /* do we need to sort outer? */
|
||||||
|
@ -3624,12 +3685,14 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
cost_sort(&sort_path,
|
cost_sort(&sort_path,
|
||||||
root,
|
root,
|
||||||
outersortkeys,
|
outersortkeys,
|
||||||
|
outer_path->disabled_nodes,
|
||||||
outer_path->total_cost,
|
outer_path->total_cost,
|
||||||
outer_path_rows,
|
outer_path_rows,
|
||||||
outer_path->pathtarget->width,
|
outer_path->pathtarget->width,
|
||||||
0.0,
|
0.0,
|
||||||
work_mem,
|
work_mem,
|
||||||
-1.0);
|
-1.0);
|
||||||
|
disabled_nodes += sort_path.disabled_nodes;
|
||||||
startup_cost += sort_path.startup_cost;
|
startup_cost += sort_path.startup_cost;
|
||||||
startup_cost += (sort_path.total_cost - sort_path.startup_cost)
|
startup_cost += (sort_path.total_cost - sort_path.startup_cost)
|
||||||
* outerstartsel;
|
* outerstartsel;
|
||||||
|
@ -3638,6 +3701,7 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
disabled_nodes += outer_path->disabled_nodes;
|
||||||
startup_cost += outer_path->startup_cost;
|
startup_cost += outer_path->startup_cost;
|
||||||
startup_cost += (outer_path->total_cost - outer_path->startup_cost)
|
startup_cost += (outer_path->total_cost - outer_path->startup_cost)
|
||||||
* outerstartsel;
|
* outerstartsel;
|
||||||
|
@ -3650,12 +3714,14 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
cost_sort(&sort_path,
|
cost_sort(&sort_path,
|
||||||
root,
|
root,
|
||||||
innersortkeys,
|
innersortkeys,
|
||||||
|
inner_path->disabled_nodes,
|
||||||
inner_path->total_cost,
|
inner_path->total_cost,
|
||||||
inner_path_rows,
|
inner_path_rows,
|
||||||
inner_path->pathtarget->width,
|
inner_path->pathtarget->width,
|
||||||
0.0,
|
0.0,
|
||||||
work_mem,
|
work_mem,
|
||||||
-1.0);
|
-1.0);
|
||||||
|
disabled_nodes += sort_path.disabled_nodes;
|
||||||
startup_cost += sort_path.startup_cost;
|
startup_cost += sort_path.startup_cost;
|
||||||
startup_cost += (sort_path.total_cost - sort_path.startup_cost)
|
startup_cost += (sort_path.total_cost - sort_path.startup_cost)
|
||||||
* innerstartsel;
|
* innerstartsel;
|
||||||
|
@ -3664,6 +3730,7 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
disabled_nodes += inner_path->disabled_nodes;
|
||||||
startup_cost += inner_path->startup_cost;
|
startup_cost += inner_path->startup_cost;
|
||||||
startup_cost += (inner_path->total_cost - inner_path->startup_cost)
|
startup_cost += (inner_path->total_cost - inner_path->startup_cost)
|
||||||
* innerstartsel;
|
* innerstartsel;
|
||||||
|
@ -3682,6 +3749,7 @@ initial_cost_mergejoin(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
/* CPU costs left for later */
|
/* CPU costs left for later */
|
||||||
|
|
||||||
/* Public result fields */
|
/* Public result fields */
|
||||||
|
workspace->disabled_nodes = disabled_nodes;
|
||||||
workspace->startup_cost = startup_cost;
|
workspace->startup_cost = startup_cost;
|
||||||
workspace->total_cost = startup_cost + run_cost + inner_run_cost;
|
workspace->total_cost = startup_cost + run_cost + inner_run_cost;
|
||||||
/* Save private data for final_cost_mergejoin */
|
/* Save private data for final_cost_mergejoin */
|
||||||
|
@ -3746,6 +3814,9 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
|
||||||
rescannedtuples;
|
rescannedtuples;
|
||||||
double rescanratio;
|
double rescanratio;
|
||||||
|
|
||||||
|
/* Set the number of disabled nodes. */
|
||||||
|
path->jpath.path.disabled_nodes = workspace->disabled_nodes;
|
||||||
|
|
||||||
/* Protect some assumptions below that rowcounts aren't zero */
|
/* Protect some assumptions below that rowcounts aren't zero */
|
||||||
if (inner_path_rows <= 0)
|
if (inner_path_rows <= 0)
|
||||||
inner_path_rows = 1;
|
inner_path_rows = 1;
|
||||||
|
@ -3765,14 +3836,6 @@ final_cost_mergejoin(PlannerInfo *root, MergePath *path,
|
||||||
clamp_row_est(path->jpath.path.rows / parallel_divisor);
|
clamp_row_est(path->jpath.path.rows / parallel_divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We could include disable_cost in the preliminary estimate, but that
|
|
||||||
* would amount to optimizing for the case where the join method is
|
|
||||||
* disabled, which doesn't seem like the way to bet.
|
|
||||||
*/
|
|
||||||
if (!enable_mergejoin)
|
|
||||||
startup_cost += disable_cost;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute cost of the mergequals and qpquals (other restriction clauses)
|
* Compute cost of the mergequals and qpquals (other restriction clauses)
|
||||||
* separately.
|
* separately.
|
||||||
|
@ -4056,6 +4119,7 @@ initial_cost_hashjoin(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
JoinPathExtraData *extra,
|
JoinPathExtraData *extra,
|
||||||
bool parallel_hash)
|
bool parallel_hash)
|
||||||
{
|
{
|
||||||
|
int disabled_nodes;
|
||||||
Cost startup_cost = 0;
|
Cost startup_cost = 0;
|
||||||
Cost run_cost = 0;
|
Cost run_cost = 0;
|
||||||
double outer_path_rows = outer_path->rows;
|
double outer_path_rows = outer_path->rows;
|
||||||
|
@ -4067,6 +4131,11 @@ initial_cost_hashjoin(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
int num_skew_mcvs;
|
int num_skew_mcvs;
|
||||||
size_t space_allowed; /* unused */
|
size_t space_allowed; /* unused */
|
||||||
|
|
||||||
|
/* Count up disabled nodes. */
|
||||||
|
disabled_nodes = enable_hashjoin ? 0 : 1;
|
||||||
|
disabled_nodes += inner_path->disabled_nodes;
|
||||||
|
disabled_nodes += outer_path->disabled_nodes;
|
||||||
|
|
||||||
/* cost of source data */
|
/* cost of source data */
|
||||||
startup_cost += outer_path->startup_cost;
|
startup_cost += outer_path->startup_cost;
|
||||||
run_cost += outer_path->total_cost - outer_path->startup_cost;
|
run_cost += outer_path->total_cost - outer_path->startup_cost;
|
||||||
|
@ -4136,6 +4205,7 @@ initial_cost_hashjoin(PlannerInfo *root, JoinCostWorkspace *workspace,
|
||||||
/* CPU costs left for later */
|
/* CPU costs left for later */
|
||||||
|
|
||||||
/* Public result fields */
|
/* Public result fields */
|
||||||
|
workspace->disabled_nodes = disabled_nodes;
|
||||||
workspace->startup_cost = startup_cost;
|
workspace->startup_cost = startup_cost;
|
||||||
workspace->total_cost = startup_cost + run_cost;
|
workspace->total_cost = startup_cost + run_cost;
|
||||||
/* Save private data for final_cost_hashjoin */
|
/* Save private data for final_cost_hashjoin */
|
||||||
|
@ -4180,6 +4250,9 @@ final_cost_hashjoin(PlannerInfo *root, HashPath *path,
|
||||||
Selectivity innermcvfreq;
|
Selectivity innermcvfreq;
|
||||||
ListCell *hcl;
|
ListCell *hcl;
|
||||||
|
|
||||||
|
/* Set the number of disabled nodes. */
|
||||||
|
path->jpath.path.disabled_nodes = workspace->disabled_nodes;
|
||||||
|
|
||||||
/* Mark the path with the correct row estimate */
|
/* Mark the path with the correct row estimate */
|
||||||
if (path->jpath.path.param_info)
|
if (path->jpath.path.param_info)
|
||||||
path->jpath.path.rows = path->jpath.path.param_info->ppi_rows;
|
path->jpath.path.rows = path->jpath.path.param_info->ppi_rows;
|
||||||
|
@ -4195,14 +4268,6 @@ final_cost_hashjoin(PlannerInfo *root, HashPath *path,
|
||||||
clamp_row_est(path->jpath.path.rows / parallel_divisor);
|
clamp_row_est(path->jpath.path.rows / parallel_divisor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* We could include disable_cost in the preliminary estimate, but that
|
|
||||||
* would amount to optimizing for the case where the join method is
|
|
||||||
* disabled, which doesn't seem like the way to bet.
|
|
||||||
*/
|
|
||||||
if (!enable_hashjoin)
|
|
||||||
startup_cost += disable_cost;
|
|
||||||
|
|
||||||
/* mark the path with estimated # of batches */
|
/* mark the path with estimated # of batches */
|
||||||
path->num_batches = numbatches;
|
path->num_batches = numbatches;
|
||||||
|
|
||||||
|
|
|
@ -915,7 +915,7 @@ try_nestloop_path(PlannerInfo *root,
|
||||||
initial_cost_nestloop(root, &workspace, jointype,
|
initial_cost_nestloop(root, &workspace, jointype,
|
||||||
outer_path, inner_path, extra);
|
outer_path, inner_path, extra);
|
||||||
|
|
||||||
if (add_path_precheck(joinrel,
|
if (add_path_precheck(joinrel, workspace.disabled_nodes,
|
||||||
workspace.startup_cost, workspace.total_cost,
|
workspace.startup_cost, workspace.total_cost,
|
||||||
pathkeys, required_outer))
|
pathkeys, required_outer))
|
||||||
{
|
{
|
||||||
|
@ -999,7 +999,8 @@ try_partial_nestloop_path(PlannerInfo *root,
|
||||||
*/
|
*/
|
||||||
initial_cost_nestloop(root, &workspace, jointype,
|
initial_cost_nestloop(root, &workspace, jointype,
|
||||||
outer_path, inner_path, extra);
|
outer_path, inner_path, extra);
|
||||||
if (!add_partial_path_precheck(joinrel, workspace.total_cost, pathkeys))
|
if (!add_partial_path_precheck(joinrel, workspace.disabled_nodes,
|
||||||
|
workspace.total_cost, pathkeys))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Might be good enough to be worth trying, so let's try it. */
|
/* Might be good enough to be worth trying, so let's try it. */
|
||||||
|
@ -1096,7 +1097,7 @@ try_mergejoin_path(PlannerInfo *root,
|
||||||
outersortkeys, innersortkeys,
|
outersortkeys, innersortkeys,
|
||||||
extra);
|
extra);
|
||||||
|
|
||||||
if (add_path_precheck(joinrel,
|
if (add_path_precheck(joinrel, workspace.disabled_nodes,
|
||||||
workspace.startup_cost, workspace.total_cost,
|
workspace.startup_cost, workspace.total_cost,
|
||||||
pathkeys, required_outer))
|
pathkeys, required_outer))
|
||||||
{
|
{
|
||||||
|
@ -1168,7 +1169,8 @@ try_partial_mergejoin_path(PlannerInfo *root,
|
||||||
outersortkeys, innersortkeys,
|
outersortkeys, innersortkeys,
|
||||||
extra);
|
extra);
|
||||||
|
|
||||||
if (!add_partial_path_precheck(joinrel, workspace.total_cost, pathkeys))
|
if (!add_partial_path_precheck(joinrel, workspace.disabled_nodes,
|
||||||
|
workspace.total_cost, pathkeys))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Might be good enough to be worth trying, so let's try it. */
|
/* Might be good enough to be worth trying, so let's try it. */
|
||||||
|
@ -1237,7 +1239,7 @@ try_hashjoin_path(PlannerInfo *root,
|
||||||
initial_cost_hashjoin(root, &workspace, jointype, hashclauses,
|
initial_cost_hashjoin(root, &workspace, jointype, hashclauses,
|
||||||
outer_path, inner_path, extra, false);
|
outer_path, inner_path, extra, false);
|
||||||
|
|
||||||
if (add_path_precheck(joinrel,
|
if (add_path_precheck(joinrel, workspace.disabled_nodes,
|
||||||
workspace.startup_cost, workspace.total_cost,
|
workspace.startup_cost, workspace.total_cost,
|
||||||
NIL, required_outer))
|
NIL, required_outer))
|
||||||
{
|
{
|
||||||
|
@ -1298,7 +1300,8 @@ try_partial_hashjoin_path(PlannerInfo *root,
|
||||||
*/
|
*/
|
||||||
initial_cost_hashjoin(root, &workspace, jointype, hashclauses,
|
initial_cost_hashjoin(root, &workspace, jointype, hashclauses,
|
||||||
outer_path, inner_path, extra, parallel_hash);
|
outer_path, inner_path, extra, parallel_hash);
|
||||||
if (!add_partial_path_precheck(joinrel, workspace.total_cost, NIL))
|
if (!add_partial_path_precheck(joinrel, workspace.disabled_nodes,
|
||||||
|
workspace.total_cost, NIL))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Might be good enough to be worth trying, so let's try it. */
|
/* Might be good enough to be worth trying, so let's try it. */
|
||||||
|
|
|
@ -5452,6 +5452,7 @@ label_sort_with_costsize(PlannerInfo *root, Sort *plan, double limit_tuples)
|
||||||
|
|
||||||
cost_sort(&sort_path, root, NIL,
|
cost_sort(&sort_path, root, NIL,
|
||||||
lefttree->total_cost,
|
lefttree->total_cost,
|
||||||
|
0, /* a Plan contains no count of disabled nodes */
|
||||||
lefttree->plan_rows,
|
lefttree->plan_rows,
|
||||||
lefttree->plan_width,
|
lefttree->plan_width,
|
||||||
0.0,
|
0.0,
|
||||||
|
@ -6546,6 +6547,7 @@ materialize_finished_plan(Plan *subplan)
|
||||||
|
|
||||||
/* Set cost data */
|
/* Set cost data */
|
||||||
cost_material(&matpath,
|
cost_material(&matpath,
|
||||||
|
0, /* a Plan contains no count of disabled nodes */
|
||||||
subplan->startup_cost,
|
subplan->startup_cost,
|
||||||
subplan->total_cost,
|
subplan->total_cost,
|
||||||
subplan->plan_rows,
|
subplan->plan_rows,
|
||||||
|
|
|
@ -6748,6 +6748,7 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid)
|
||||||
/* Estimate the cost of seq scan + sort */
|
/* Estimate the cost of seq scan + sort */
|
||||||
seqScanPath = create_seqscan_path(root, rel, NULL, 0);
|
seqScanPath = create_seqscan_path(root, rel, NULL, 0);
|
||||||
cost_sort(&seqScanAndSortPath, root, NIL,
|
cost_sort(&seqScanAndSortPath, root, NIL,
|
||||||
|
seqScanPath->disabled_nodes,
|
||||||
seqScanPath->total_cost, rel->tuples, rel->reltarget->width,
|
seqScanPath->total_cost, rel->tuples, rel->reltarget->width,
|
||||||
comparisonCost, maintenance_work_mem, -1.0);
|
comparisonCost, maintenance_work_mem, -1.0);
|
||||||
|
|
||||||
|
|
|
@ -1346,6 +1346,7 @@ choose_hashed_setop(PlannerInfo *root, List *groupClauses,
|
||||||
cost_agg(&hashed_p, root, AGG_HASHED, NULL,
|
cost_agg(&hashed_p, root, AGG_HASHED, NULL,
|
||||||
numGroupCols, dNumGroups,
|
numGroupCols, dNumGroups,
|
||||||
NIL,
|
NIL,
|
||||||
|
input_path->disabled_nodes,
|
||||||
input_path->startup_cost, input_path->total_cost,
|
input_path->startup_cost, input_path->total_cost,
|
||||||
input_path->rows, input_path->pathtarget->width);
|
input_path->rows, input_path->pathtarget->width);
|
||||||
|
|
||||||
|
@ -1353,14 +1354,17 @@ choose_hashed_setop(PlannerInfo *root, List *groupClauses,
|
||||||
* Now for the sorted case. Note that the input is *always* unsorted,
|
* Now for the sorted case. Note that the input is *always* unsorted,
|
||||||
* since it was made by appending unrelated sub-relations together.
|
* since it was made by appending unrelated sub-relations together.
|
||||||
*/
|
*/
|
||||||
|
sorted_p.disabled_nodes = input_path->disabled_nodes;
|
||||||
sorted_p.startup_cost = input_path->startup_cost;
|
sorted_p.startup_cost = input_path->startup_cost;
|
||||||
sorted_p.total_cost = input_path->total_cost;
|
sorted_p.total_cost = input_path->total_cost;
|
||||||
/* XXX cost_sort doesn't actually look at pathkeys, so just pass NIL */
|
/* XXX cost_sort doesn't actually look at pathkeys, so just pass NIL */
|
||||||
cost_sort(&sorted_p, root, NIL, sorted_p.total_cost,
|
cost_sort(&sorted_p, root, NIL, sorted_p.disabled_nodes,
|
||||||
|
sorted_p.total_cost,
|
||||||
input_path->rows, input_path->pathtarget->width,
|
input_path->rows, input_path->pathtarget->width,
|
||||||
0.0, work_mem, -1.0);
|
0.0, work_mem, -1.0);
|
||||||
cost_group(&sorted_p, root, numGroupCols, dNumGroups,
|
cost_group(&sorted_p, root, numGroupCols, dNumGroups,
|
||||||
NIL,
|
NIL,
|
||||||
|
sorted_p.disabled_nodes,
|
||||||
sorted_p.startup_cost, sorted_p.total_cost,
|
sorted_p.startup_cost, sorted_p.total_cost,
|
||||||
input_path->rows);
|
input_path->rows);
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,15 @@ static bool pathlist_is_reparameterizable_by_child(List *pathlist,
|
||||||
int
|
int
|
||||||
compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
|
compare_path_costs(Path *path1, Path *path2, CostSelector criterion)
|
||||||
{
|
{
|
||||||
|
/* Number of disabled nodes, if different, trumps all else. */
|
||||||
|
if (unlikely(path1->disabled_nodes != path2->disabled_nodes))
|
||||||
|
{
|
||||||
|
if (path1->disabled_nodes < path2->disabled_nodes)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
|
||||||
if (criterion == STARTUP_COST)
|
if (criterion == STARTUP_COST)
|
||||||
{
|
{
|
||||||
if (path1->startup_cost < path2->startup_cost)
|
if (path1->startup_cost < path2->startup_cost)
|
||||||
|
@ -118,6 +127,15 @@ compare_fractional_path_costs(Path *path1, Path *path2,
|
||||||
Cost cost1,
|
Cost cost1,
|
||||||
cost2;
|
cost2;
|
||||||
|
|
||||||
|
/* Number of disabled nodes, if different, trumps all else. */
|
||||||
|
if (unlikely(path1->disabled_nodes != path2->disabled_nodes))
|
||||||
|
{
|
||||||
|
if (path1->disabled_nodes < path2->disabled_nodes)
|
||||||
|
return -1;
|
||||||
|
else
|
||||||
|
return +1;
|
||||||
|
}
|
||||||
|
|
||||||
if (fraction <= 0.0 || fraction >= 1.0)
|
if (fraction <= 0.0 || fraction >= 1.0)
|
||||||
return compare_path_costs(path1, path2, TOTAL_COST);
|
return compare_path_costs(path1, path2, TOTAL_COST);
|
||||||
cost1 = path1->startup_cost +
|
cost1 = path1->startup_cost +
|
||||||
|
@ -166,6 +184,15 @@ compare_path_costs_fuzzily(Path *path1, Path *path2, double fuzz_factor)
|
||||||
#define CONSIDER_PATH_STARTUP_COST(p) \
|
#define CONSIDER_PATH_STARTUP_COST(p) \
|
||||||
((p)->param_info == NULL ? (p)->parent->consider_startup : (p)->parent->consider_param_startup)
|
((p)->param_info == NULL ? (p)->parent->consider_startup : (p)->parent->consider_param_startup)
|
||||||
|
|
||||||
|
/* Number of disabled nodes, if different, trumps all else. */
|
||||||
|
if (unlikely(path1->disabled_nodes != path2->disabled_nodes))
|
||||||
|
{
|
||||||
|
if (path1->disabled_nodes < path2->disabled_nodes)
|
||||||
|
return COSTS_BETTER1;
|
||||||
|
else
|
||||||
|
return COSTS_BETTER2;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check total cost first since it's more likely to be different; many
|
* Check total cost first since it's more likely to be different; many
|
||||||
* paths have zero startup cost.
|
* paths have zero startup cost.
|
||||||
|
@ -362,15 +389,29 @@ set_cheapest(RelOptInfo *parent_rel)
|
||||||
* add_path
|
* add_path
|
||||||
* Consider a potential implementation path for the specified parent rel,
|
* Consider a potential implementation path for the specified parent rel,
|
||||||
* and add it to the rel's pathlist if it is worthy of consideration.
|
* and add it to the rel's pathlist if it is worthy of consideration.
|
||||||
* A path is worthy if it has a better sort order (better pathkeys) or
|
|
||||||
* cheaper cost (on either dimension), or generates fewer rows, than any
|
|
||||||
* existing path that has the same or superset parameterization rels.
|
|
||||||
* We also consider parallel-safe paths more worthy than others.
|
|
||||||
*
|
*
|
||||||
* We also remove from the rel's pathlist any old paths that are dominated
|
* A path is worthy if it has a better sort order (better pathkeys) or
|
||||||
* by new_path --- that is, new_path is cheaper, at least as well ordered,
|
* cheaper cost (as defined below), or generates fewer rows, than any
|
||||||
* generates no more rows, requires no outer rels not required by the old
|
* existing path that has the same or superset parameterization rels. We
|
||||||
* path, and is no less parallel-safe.
|
* also consider parallel-safe paths more worthy than others.
|
||||||
|
*
|
||||||
|
* Cheaper cost can mean either a cheaper total cost or a cheaper startup
|
||||||
|
* cost; if one path is cheaper in one of these aspects and another is
|
||||||
|
* cheaper in the other, we keep both. However, when some path type is
|
||||||
|
* disabled (e.g. due to enable_seqscan=false), the number of times that
|
||||||
|
* a disabled path type is used is considered to be a higher-order
|
||||||
|
* component of the cost. Hence, if path A uses no disabled path type,
|
||||||
|
* and path B uses 1 or more disabled path types, A is cheaper, no matter
|
||||||
|
* what we estimate for the startup and total costs. The startup and total
|
||||||
|
* cost essentially act as a tiebreak when comparing paths that use equal
|
||||||
|
* numbers of disabled path nodes; but in practice this tiebreak is almost
|
||||||
|
* always used, since normally no path types are disabled.
|
||||||
|
*
|
||||||
|
* In addition to possibly adding new_path, we also remove from the rel's
|
||||||
|
* pathlist any old paths that are dominated by new_path --- that is,
|
||||||
|
* new_path is cheaper, at least as well ordered, generates no more rows,
|
||||||
|
* requires no outer rels not required by the old path, and is no less
|
||||||
|
* parallel-safe.
|
||||||
*
|
*
|
||||||
* In most cases, a path with a superset parameterization will generate
|
* In most cases, a path with a superset parameterization will generate
|
||||||
* fewer rows (since it has more join clauses to apply), so that those two
|
* fewer rows (since it has more join clauses to apply), so that those two
|
||||||
|
@ -389,10 +430,10 @@ set_cheapest(RelOptInfo *parent_rel)
|
||||||
* parent_rel->consider_param_startup is true for a parameterized one.
|
* parent_rel->consider_param_startup is true for a parameterized one.
|
||||||
* Again, this allows discarding useless paths sooner.
|
* Again, this allows discarding useless paths sooner.
|
||||||
*
|
*
|
||||||
* The pathlist is kept sorted by total_cost, with cheaper paths
|
* The pathlist is kept sorted by disabled_nodes and then by total_cost,
|
||||||
* at the front. Within this routine, that's simply a speed hack:
|
* with cheaper paths at the front. Within this routine, that's simply a
|
||||||
* doing it that way makes it more likely that we will reject an inferior
|
* speed hack: doing it that way makes it more likely that we will reject
|
||||||
* path after a few comparisons, rather than many comparisons.
|
* an inferior path after a few comparisons, rather than many comparisons.
|
||||||
* However, add_path_precheck relies on this ordering to exit early
|
* However, add_path_precheck relies on this ordering to exit early
|
||||||
* when possible.
|
* when possible.
|
||||||
*
|
*
|
||||||
|
@ -593,8 +634,13 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* new belongs after this old path if it has cost >= old's */
|
/*
|
||||||
if (new_path->total_cost >= old_path->total_cost)
|
* new belongs after this old path if it has more disabled nodes
|
||||||
|
* or if it has the same number of nodes but a greater total cost
|
||||||
|
*/
|
||||||
|
if (new_path->disabled_nodes > old_path->disabled_nodes ||
|
||||||
|
(new_path->disabled_nodes == old_path->disabled_nodes &&
|
||||||
|
new_path->total_cost >= old_path->total_cost))
|
||||||
insert_at = foreach_current_index(p1) + 1;
|
insert_at = foreach_current_index(p1) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -639,7 +685,7 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
|
||||||
* so the required information has to be passed piecemeal.
|
* so the required information has to be passed piecemeal.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
add_path_precheck(RelOptInfo *parent_rel,
|
add_path_precheck(RelOptInfo *parent_rel, int disabled_nodes,
|
||||||
Cost startup_cost, Cost total_cost,
|
Cost startup_cost, Cost total_cost,
|
||||||
List *pathkeys, Relids required_outer)
|
List *pathkeys, Relids required_outer)
|
||||||
{
|
{
|
||||||
|
@ -658,6 +704,20 @@ add_path_precheck(RelOptInfo *parent_rel,
|
||||||
Path *old_path = (Path *) lfirst(p1);
|
Path *old_path = (Path *) lfirst(p1);
|
||||||
PathKeysComparison keyscmp;
|
PathKeysComparison keyscmp;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since the pathlist is sorted by disabled_nodes and then by
|
||||||
|
* total_cost, we can stop looking once we reach a path with more
|
||||||
|
* disabled nodes, or the same number of disabled nodes plus a
|
||||||
|
* total_cost larger than the new path's.
|
||||||
|
*/
|
||||||
|
if (unlikely(old_path->disabled_nodes != disabled_nodes))
|
||||||
|
{
|
||||||
|
if (disabled_nodes < old_path->disabled_nodes)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (total_cost <= old_path->total_cost * STD_FUZZ_FACTOR)
|
||||||
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We are looking for an old_path with the same parameterization (and
|
* We are looking for an old_path with the same parameterization (and
|
||||||
* by assumption the same rowcount) that dominates the new path on
|
* by assumption the same rowcount) that dominates the new path on
|
||||||
|
@ -666,8 +726,6 @@ add_path_precheck(RelOptInfo *parent_rel,
|
||||||
*
|
*
|
||||||
* Cost comparisons here should match compare_path_costs_fuzzily.
|
* Cost comparisons here should match compare_path_costs_fuzzily.
|
||||||
*/
|
*/
|
||||||
if (total_cost > old_path->total_cost * STD_FUZZ_FACTOR)
|
|
||||||
{
|
|
||||||
/* new path can win on startup cost only if consider_startup */
|
/* new path can win on startup cost only if consider_startup */
|
||||||
if (startup_cost > old_path->startup_cost * STD_FUZZ_FACTOR ||
|
if (startup_cost > old_path->startup_cost * STD_FUZZ_FACTOR ||
|
||||||
!consider_startup)
|
!consider_startup)
|
||||||
|
@ -690,16 +748,6 @@ add_path_precheck(RelOptInfo *parent_rel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Since the pathlist is sorted by total_cost, we can stop looking
|
|
||||||
* once we reach a path with a total_cost larger than the new
|
|
||||||
* path's.
|
|
||||||
*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -734,7 +782,7 @@ add_path_precheck(RelOptInfo *parent_rel,
|
||||||
* produce the same number of rows. Neither do we need to consider startup
|
* produce the same number of rows. Neither do we need to consider startup
|
||||||
* costs: parallelism is only used for plans that will be run to completion.
|
* costs: parallelism is only used for plans that will be run to completion.
|
||||||
* Therefore, this routine is much simpler than add_path: it needs to
|
* Therefore, this routine is much simpler than add_path: it needs to
|
||||||
* consider only pathkeys and total cost.
|
* consider only disabled nodes, pathkeys and total cost.
|
||||||
*
|
*
|
||||||
* As with add_path, we pfree paths that are found to be dominated by
|
* As with add_path, we pfree paths that are found to be dominated by
|
||||||
* another partial path; this requires that there be no other references to
|
* another partial path; this requires that there be no other references to
|
||||||
|
@ -775,7 +823,15 @@ add_partial_path(RelOptInfo *parent_rel, Path *new_path)
|
||||||
/* Unless pathkeys are incompatible, keep just one of the two paths. */
|
/* Unless pathkeys are incompatible, keep just one of the two paths. */
|
||||||
if (keyscmp != PATHKEYS_DIFFERENT)
|
if (keyscmp != PATHKEYS_DIFFERENT)
|
||||||
{
|
{
|
||||||
if (new_path->total_cost > old_path->total_cost * STD_FUZZ_FACTOR)
|
if (unlikely(new_path->disabled_nodes != old_path->disabled_nodes))
|
||||||
|
{
|
||||||
|
if (new_path->disabled_nodes > old_path->disabled_nodes)
|
||||||
|
accept_new = false;
|
||||||
|
else
|
||||||
|
remove_old = true;
|
||||||
|
}
|
||||||
|
else if (new_path->total_cost > old_path->total_cost
|
||||||
|
* STD_FUZZ_FACTOR)
|
||||||
{
|
{
|
||||||
/* New path costs more; keep it only if pathkeys are better. */
|
/* New path costs more; keep it only if pathkeys are better. */
|
||||||
if (keyscmp != PATHKEYS_BETTER1)
|
if (keyscmp != PATHKEYS_BETTER1)
|
||||||
|
@ -862,8 +918,8 @@ add_partial_path(RelOptInfo *parent_rel, Path *new_path)
|
||||||
* is surely a loser.
|
* is surely a loser.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
add_partial_path_precheck(RelOptInfo *parent_rel, Cost total_cost,
|
add_partial_path_precheck(RelOptInfo *parent_rel, int disabled_nodes,
|
||||||
List *pathkeys)
|
Cost total_cost, List *pathkeys)
|
||||||
{
|
{
|
||||||
ListCell *p1;
|
ListCell *p1;
|
||||||
|
|
||||||
|
@ -906,8 +962,8 @@ add_partial_path_precheck(RelOptInfo *parent_rel, Cost total_cost,
|
||||||
* partial path; the resulting plans, if run in parallel, will be run to
|
* partial path; the resulting plans, if run in parallel, will be run to
|
||||||
* completion.
|
* completion.
|
||||||
*/
|
*/
|
||||||
if (!add_path_precheck(parent_rel, total_cost, total_cost, pathkeys,
|
if (!add_path_precheck(parent_rel, disabled_nodes, total_cost, total_cost,
|
||||||
NULL))
|
pathkeys, NULL))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -1419,6 +1475,7 @@ create_merge_append_path(PlannerInfo *root,
|
||||||
Relids required_outer)
|
Relids required_outer)
|
||||||
{
|
{
|
||||||
MergeAppendPath *pathnode = makeNode(MergeAppendPath);
|
MergeAppendPath *pathnode = makeNode(MergeAppendPath);
|
||||||
|
int input_disabled_nodes;
|
||||||
Cost input_startup_cost;
|
Cost input_startup_cost;
|
||||||
Cost input_total_cost;
|
Cost input_total_cost;
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
@ -1452,6 +1509,7 @@ create_merge_append_path(PlannerInfo *root,
|
||||||
* Add up the sizes and costs of the input paths.
|
* Add up the sizes and costs of the input paths.
|
||||||
*/
|
*/
|
||||||
pathnode->path.rows = 0;
|
pathnode->path.rows = 0;
|
||||||
|
input_disabled_nodes = 0;
|
||||||
input_startup_cost = 0;
|
input_startup_cost = 0;
|
||||||
input_total_cost = 0;
|
input_total_cost = 0;
|
||||||
foreach(l, subpaths)
|
foreach(l, subpaths)
|
||||||
|
@ -1468,6 +1526,7 @@ create_merge_append_path(PlannerInfo *root,
|
||||||
if (pathkeys_contained_in(pathkeys, subpath->pathkeys))
|
if (pathkeys_contained_in(pathkeys, subpath->pathkeys))
|
||||||
{
|
{
|
||||||
/* Subpath is adequately ordered, we won't need to sort it */
|
/* Subpath is adequately ordered, we won't need to sort it */
|
||||||
|
input_disabled_nodes += subpath->disabled_nodes;
|
||||||
input_startup_cost += subpath->startup_cost;
|
input_startup_cost += subpath->startup_cost;
|
||||||
input_total_cost += subpath->total_cost;
|
input_total_cost += subpath->total_cost;
|
||||||
}
|
}
|
||||||
|
@ -1479,12 +1538,14 @@ create_merge_append_path(PlannerInfo *root,
|
||||||
cost_sort(&sort_path,
|
cost_sort(&sort_path,
|
||||||
root,
|
root,
|
||||||
pathkeys,
|
pathkeys,
|
||||||
|
subpath->disabled_nodes,
|
||||||
subpath->total_cost,
|
subpath->total_cost,
|
||||||
subpath->rows,
|
subpath->rows,
|
||||||
subpath->pathtarget->width,
|
subpath->pathtarget->width,
|
||||||
0.0,
|
0.0,
|
||||||
work_mem,
|
work_mem,
|
||||||
pathnode->limit_tuples);
|
pathnode->limit_tuples);
|
||||||
|
input_disabled_nodes += sort_path.disabled_nodes;
|
||||||
input_startup_cost += sort_path.startup_cost;
|
input_startup_cost += sort_path.startup_cost;
|
||||||
input_total_cost += sort_path.total_cost;
|
input_total_cost += sort_path.total_cost;
|
||||||
}
|
}
|
||||||
|
@ -1500,12 +1561,14 @@ create_merge_append_path(PlannerInfo *root,
|
||||||
((Path *) linitial(subpaths))->parallel_aware ==
|
((Path *) linitial(subpaths))->parallel_aware ==
|
||||||
pathnode->path.parallel_aware)
|
pathnode->path.parallel_aware)
|
||||||
{
|
{
|
||||||
|
pathnode->path.disabled_nodes = input_disabled_nodes;
|
||||||
pathnode->path.startup_cost = input_startup_cost;
|
pathnode->path.startup_cost = input_startup_cost;
|
||||||
pathnode->path.total_cost = input_total_cost;
|
pathnode->path.total_cost = input_total_cost;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
cost_merge_append(&pathnode->path, root,
|
cost_merge_append(&pathnode->path, root,
|
||||||
pathkeys, list_length(subpaths),
|
pathkeys, list_length(subpaths),
|
||||||
|
input_disabled_nodes,
|
||||||
input_startup_cost, input_total_cost,
|
input_startup_cost, input_total_cost,
|
||||||
pathnode->path.rows);
|
pathnode->path.rows);
|
||||||
|
|
||||||
|
@ -1587,6 +1650,7 @@ create_material_path(RelOptInfo *rel, Path *subpath)
|
||||||
pathnode->subpath = subpath;
|
pathnode->subpath = subpath;
|
||||||
|
|
||||||
cost_material(&pathnode->path,
|
cost_material(&pathnode->path,
|
||||||
|
subpath->disabled_nodes,
|
||||||
subpath->startup_cost,
|
subpath->startup_cost,
|
||||||
subpath->total_cost,
|
subpath->total_cost,
|
||||||
subpath->rows,
|
subpath->rows,
|
||||||
|
@ -1633,6 +1697,10 @@ create_memoize_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
|
||||||
*/
|
*/
|
||||||
pathnode->est_entries = 0;
|
pathnode->est_entries = 0;
|
||||||
|
|
||||||
|
/* we should not generate this path type when enable_memoize=false */
|
||||||
|
Assert(enable_memoize);
|
||||||
|
pathnode->path.disabled_nodes = subpath->disabled_nodes;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add a small additional charge for caching the first entry. All the
|
* Add a small additional charge for caching the first entry. All the
|
||||||
* harder calculations for rescans are performed in cost_memoize_rescan().
|
* harder calculations for rescans are performed in cost_memoize_rescan().
|
||||||
|
@ -1732,6 +1800,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
|
||||||
{
|
{
|
||||||
pathnode->umethod = UNIQUE_PATH_NOOP;
|
pathnode->umethod = UNIQUE_PATH_NOOP;
|
||||||
pathnode->path.rows = rel->rows;
|
pathnode->path.rows = rel->rows;
|
||||||
|
pathnode->path.disabled_nodes = subpath->disabled_nodes;
|
||||||
pathnode->path.startup_cost = subpath->startup_cost;
|
pathnode->path.startup_cost = subpath->startup_cost;
|
||||||
pathnode->path.total_cost = subpath->total_cost;
|
pathnode->path.total_cost = subpath->total_cost;
|
||||||
pathnode->path.pathkeys = subpath->pathkeys;
|
pathnode->path.pathkeys = subpath->pathkeys;
|
||||||
|
@ -1770,6 +1839,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
|
||||||
{
|
{
|
||||||
pathnode->umethod = UNIQUE_PATH_NOOP;
|
pathnode->umethod = UNIQUE_PATH_NOOP;
|
||||||
pathnode->path.rows = rel->rows;
|
pathnode->path.rows = rel->rows;
|
||||||
|
pathnode->path.disabled_nodes = subpath->disabled_nodes;
|
||||||
pathnode->path.startup_cost = subpath->startup_cost;
|
pathnode->path.startup_cost = subpath->startup_cost;
|
||||||
pathnode->path.total_cost = subpath->total_cost;
|
pathnode->path.total_cost = subpath->total_cost;
|
||||||
pathnode->path.pathkeys = subpath->pathkeys;
|
pathnode->path.pathkeys = subpath->pathkeys;
|
||||||
|
@ -1797,6 +1867,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
|
||||||
* Estimate cost for sort+unique implementation
|
* Estimate cost for sort+unique implementation
|
||||||
*/
|
*/
|
||||||
cost_sort(&sort_path, root, NIL,
|
cost_sort(&sort_path, root, NIL,
|
||||||
|
subpath->disabled_nodes,
|
||||||
subpath->total_cost,
|
subpath->total_cost,
|
||||||
rel->rows,
|
rel->rows,
|
||||||
subpath->pathtarget->width,
|
subpath->pathtarget->width,
|
||||||
|
@ -1834,6 +1905,7 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
|
||||||
AGG_HASHED, NULL,
|
AGG_HASHED, NULL,
|
||||||
numCols, pathnode->path.rows,
|
numCols, pathnode->path.rows,
|
||||||
NIL,
|
NIL,
|
||||||
|
subpath->disabled_nodes,
|
||||||
subpath->startup_cost,
|
subpath->startup_cost,
|
||||||
subpath->total_cost,
|
subpath->total_cost,
|
||||||
rel->rows,
|
rel->rows,
|
||||||
|
@ -1842,7 +1914,9 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
|
||||||
|
|
||||||
if (sjinfo->semi_can_btree && sjinfo->semi_can_hash)
|
if (sjinfo->semi_can_btree && sjinfo->semi_can_hash)
|
||||||
{
|
{
|
||||||
if (agg_path.total_cost < sort_path.total_cost)
|
if (agg_path.disabled_nodes < sort_path.disabled_nodes ||
|
||||||
|
(agg_path.disabled_nodes == sort_path.disabled_nodes &&
|
||||||
|
agg_path.total_cost < sort_path.total_cost))
|
||||||
pathnode->umethod = UNIQUE_PATH_HASH;
|
pathnode->umethod = UNIQUE_PATH_HASH;
|
||||||
else
|
else
|
||||||
pathnode->umethod = UNIQUE_PATH_SORT;
|
pathnode->umethod = UNIQUE_PATH_SORT;
|
||||||
|
@ -1860,11 +1934,13 @@ create_unique_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
|
||||||
|
|
||||||
if (pathnode->umethod == UNIQUE_PATH_HASH)
|
if (pathnode->umethod == UNIQUE_PATH_HASH)
|
||||||
{
|
{
|
||||||
|
pathnode->path.disabled_nodes = agg_path.disabled_nodes;
|
||||||
pathnode->path.startup_cost = agg_path.startup_cost;
|
pathnode->path.startup_cost = agg_path.startup_cost;
|
||||||
pathnode->path.total_cost = agg_path.total_cost;
|
pathnode->path.total_cost = agg_path.total_cost;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
pathnode->path.disabled_nodes = sort_path.disabled_nodes;
|
||||||
pathnode->path.startup_cost = sort_path.startup_cost;
|
pathnode->path.startup_cost = sort_path.startup_cost;
|
||||||
pathnode->path.total_cost = sort_path.total_cost;
|
pathnode->path.total_cost = sort_path.total_cost;
|
||||||
}
|
}
|
||||||
|
@ -1888,6 +1964,7 @@ create_gather_merge_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
|
||||||
Relids required_outer, double *rows)
|
Relids required_outer, double *rows)
|
||||||
{
|
{
|
||||||
GatherMergePath *pathnode = makeNode(GatherMergePath);
|
GatherMergePath *pathnode = makeNode(GatherMergePath);
|
||||||
|
int input_disabled_nodes = 0;
|
||||||
Cost input_startup_cost = 0;
|
Cost input_startup_cost = 0;
|
||||||
Cost input_total_cost = 0;
|
Cost input_total_cost = 0;
|
||||||
|
|
||||||
|
@ -1915,11 +1992,13 @@ create_gather_merge_path(PlannerInfo *root, RelOptInfo *rel, Path *subpath,
|
||||||
pathnode->path.pathkeys = pathkeys;
|
pathnode->path.pathkeys = pathkeys;
|
||||||
pathnode->path.pathtarget = target ? target : rel->reltarget;
|
pathnode->path.pathtarget = target ? target : rel->reltarget;
|
||||||
|
|
||||||
|
input_disabled_nodes += subpath->disabled_nodes;
|
||||||
input_startup_cost += subpath->startup_cost;
|
input_startup_cost += subpath->startup_cost;
|
||||||
input_total_cost += subpath->total_cost;
|
input_total_cost += subpath->total_cost;
|
||||||
|
|
||||||
cost_gather_merge(pathnode, root, rel, pathnode->path.param_info,
|
cost_gather_merge(pathnode, root, rel, pathnode->path.param_info,
|
||||||
input_startup_cost, input_total_cost, rows);
|
input_disabled_nodes, input_startup_cost,
|
||||||
|
input_total_cost, rows);
|
||||||
|
|
||||||
return pathnode;
|
return pathnode;
|
||||||
}
|
}
|
||||||
|
@ -2227,7 +2306,8 @@ create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
ForeignPath *
|
ForeignPath *
|
||||||
create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
double rows, Cost startup_cost, Cost total_cost,
|
double rows, int disabled_nodes,
|
||||||
|
Cost startup_cost, Cost total_cost,
|
||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Relids required_outer,
|
Relids required_outer,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
|
@ -2248,6 +2328,7 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
pathnode->path.parallel_safe = rel->consider_parallel;
|
pathnode->path.parallel_safe = rel->consider_parallel;
|
||||||
pathnode->path.parallel_workers = 0;
|
pathnode->path.parallel_workers = 0;
|
||||||
pathnode->path.rows = rows;
|
pathnode->path.rows = rows;
|
||||||
|
pathnode->path.disabled_nodes = disabled_nodes;
|
||||||
pathnode->path.startup_cost = startup_cost;
|
pathnode->path.startup_cost = startup_cost;
|
||||||
pathnode->path.total_cost = total_cost;
|
pathnode->path.total_cost = total_cost;
|
||||||
pathnode->path.pathkeys = pathkeys;
|
pathnode->path.pathkeys = pathkeys;
|
||||||
|
@ -2273,7 +2354,8 @@ create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
ForeignPath *
|
ForeignPath *
|
||||||
create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
double rows, Cost startup_cost, Cost total_cost,
|
double rows, int disabled_nodes,
|
||||||
|
Cost startup_cost, Cost total_cost,
|
||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Relids required_outer,
|
Relids required_outer,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
|
@ -2300,6 +2382,7 @@ create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
pathnode->path.parallel_safe = rel->consider_parallel;
|
pathnode->path.parallel_safe = rel->consider_parallel;
|
||||||
pathnode->path.parallel_workers = 0;
|
pathnode->path.parallel_workers = 0;
|
||||||
pathnode->path.rows = rows;
|
pathnode->path.rows = rows;
|
||||||
|
pathnode->path.disabled_nodes = disabled_nodes;
|
||||||
pathnode->path.startup_cost = startup_cost;
|
pathnode->path.startup_cost = startup_cost;
|
||||||
pathnode->path.total_cost = total_cost;
|
pathnode->path.total_cost = total_cost;
|
||||||
pathnode->path.pathkeys = pathkeys;
|
pathnode->path.pathkeys = pathkeys;
|
||||||
|
@ -2325,7 +2408,8 @@ create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
ForeignPath *
|
ForeignPath *
|
||||||
create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
|
create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
double rows, Cost startup_cost, Cost total_cost,
|
double rows, int disabled_nodes,
|
||||||
|
Cost startup_cost, Cost total_cost,
|
||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
List *fdw_restrictinfo,
|
List *fdw_restrictinfo,
|
||||||
|
@ -2347,6 +2431,7 @@ create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
pathnode->path.parallel_safe = rel->consider_parallel;
|
pathnode->path.parallel_safe = rel->consider_parallel;
|
||||||
pathnode->path.parallel_workers = 0;
|
pathnode->path.parallel_workers = 0;
|
||||||
pathnode->path.rows = rows;
|
pathnode->path.rows = rows;
|
||||||
|
pathnode->path.disabled_nodes = disabled_nodes;
|
||||||
pathnode->path.startup_cost = startup_cost;
|
pathnode->path.startup_cost = startup_cost;
|
||||||
pathnode->path.total_cost = total_cost;
|
pathnode->path.total_cost = total_cost;
|
||||||
pathnode->path.pathkeys = pathkeys;
|
pathnode->path.pathkeys = pathkeys;
|
||||||
|
@ -2734,6 +2819,7 @@ create_projection_path(PlannerInfo *root,
|
||||||
* Set cost of plan as subpath's cost, adjusted for tlist replacement.
|
* Set cost of plan as subpath's cost, adjusted for tlist replacement.
|
||||||
*/
|
*/
|
||||||
pathnode->path.rows = subpath->rows;
|
pathnode->path.rows = subpath->rows;
|
||||||
|
pathnode->path.disabled_nodes = subpath->disabled_nodes;
|
||||||
pathnode->path.startup_cost = subpath->startup_cost +
|
pathnode->path.startup_cost = subpath->startup_cost +
|
||||||
(target->cost.startup - oldtarget->cost.startup);
|
(target->cost.startup - oldtarget->cost.startup);
|
||||||
pathnode->path.total_cost = subpath->total_cost +
|
pathnode->path.total_cost = subpath->total_cost +
|
||||||
|
@ -2750,6 +2836,7 @@ create_projection_path(PlannerInfo *root,
|
||||||
* evaluating the tlist. There is no qual to worry about.
|
* evaluating the tlist. There is no qual to worry about.
|
||||||
*/
|
*/
|
||||||
pathnode->path.rows = subpath->rows;
|
pathnode->path.rows = subpath->rows;
|
||||||
|
pathnode->path.disabled_nodes = subpath->disabled_nodes;
|
||||||
pathnode->path.startup_cost = subpath->startup_cost +
|
pathnode->path.startup_cost = subpath->startup_cost +
|
||||||
target->cost.startup;
|
target->cost.startup;
|
||||||
pathnode->path.total_cost = subpath->total_cost +
|
pathnode->path.total_cost = subpath->total_cost +
|
||||||
|
@ -2917,6 +3004,7 @@ create_set_projection_path(PlannerInfo *root,
|
||||||
* This is slightly bizarre maybe, but it's what 9.6 did; we may revisit
|
* This is slightly bizarre maybe, but it's what 9.6 did; we may revisit
|
||||||
* this estimate later.
|
* this estimate later.
|
||||||
*/
|
*/
|
||||||
|
pathnode->path.disabled_nodes = subpath->disabled_nodes;
|
||||||
pathnode->path.rows = subpath->rows * tlist_rows;
|
pathnode->path.rows = subpath->rows * tlist_rows;
|
||||||
pathnode->path.startup_cost = subpath->startup_cost +
|
pathnode->path.startup_cost = subpath->startup_cost +
|
||||||
target->cost.startup;
|
target->cost.startup;
|
||||||
|
@ -2967,6 +3055,7 @@ create_incremental_sort_path(PlannerInfo *root,
|
||||||
|
|
||||||
cost_incremental_sort(&pathnode->path,
|
cost_incremental_sort(&pathnode->path,
|
||||||
root, pathkeys, presorted_keys,
|
root, pathkeys, presorted_keys,
|
||||||
|
subpath->disabled_nodes,
|
||||||
subpath->startup_cost,
|
subpath->startup_cost,
|
||||||
subpath->total_cost,
|
subpath->total_cost,
|
||||||
subpath->rows,
|
subpath->rows,
|
||||||
|
@ -3013,6 +3102,7 @@ create_sort_path(PlannerInfo *root,
|
||||||
pathnode->subpath = subpath;
|
pathnode->subpath = subpath;
|
||||||
|
|
||||||
cost_sort(&pathnode->path, root, pathkeys,
|
cost_sort(&pathnode->path, root, pathkeys,
|
||||||
|
subpath->disabled_nodes,
|
||||||
subpath->total_cost,
|
subpath->total_cost,
|
||||||
subpath->rows,
|
subpath->rows,
|
||||||
subpath->pathtarget->width,
|
subpath->pathtarget->width,
|
||||||
|
@ -3065,6 +3155,7 @@ create_group_path(PlannerInfo *root,
|
||||||
list_length(groupClause),
|
list_length(groupClause),
|
||||||
numGroups,
|
numGroups,
|
||||||
qual,
|
qual,
|
||||||
|
subpath->disabled_nodes,
|
||||||
subpath->startup_cost, subpath->total_cost,
|
subpath->startup_cost, subpath->total_cost,
|
||||||
subpath->rows);
|
subpath->rows);
|
||||||
|
|
||||||
|
@ -3122,6 +3213,7 @@ create_upper_unique_path(PlannerInfo *root,
|
||||||
* all columns get compared at most of the tuples. (XXX probably this is
|
* all columns get compared at most of the tuples. (XXX probably this is
|
||||||
* an overestimate.)
|
* an overestimate.)
|
||||||
*/
|
*/
|
||||||
|
pathnode->path.disabled_nodes = subpath->disabled_nodes;
|
||||||
pathnode->path.startup_cost = subpath->startup_cost;
|
pathnode->path.startup_cost = subpath->startup_cost;
|
||||||
pathnode->path.total_cost = subpath->total_cost +
|
pathnode->path.total_cost = subpath->total_cost +
|
||||||
cpu_operator_cost * subpath->rows * numCols;
|
cpu_operator_cost * subpath->rows * numCols;
|
||||||
|
@ -3200,6 +3292,7 @@ create_agg_path(PlannerInfo *root,
|
||||||
aggstrategy, aggcosts,
|
aggstrategy, aggcosts,
|
||||||
list_length(groupClause), numGroups,
|
list_length(groupClause), numGroups,
|
||||||
qual,
|
qual,
|
||||||
|
subpath->disabled_nodes,
|
||||||
subpath->startup_cost, subpath->total_cost,
|
subpath->startup_cost, subpath->total_cost,
|
||||||
subpath->rows, subpath->pathtarget->width);
|
subpath->rows, subpath->pathtarget->width);
|
||||||
|
|
||||||
|
@ -3308,6 +3401,7 @@ create_groupingsets_path(PlannerInfo *root,
|
||||||
numGroupCols,
|
numGroupCols,
|
||||||
rollup->numGroups,
|
rollup->numGroups,
|
||||||
having_qual,
|
having_qual,
|
||||||
|
subpath->disabled_nodes,
|
||||||
subpath->startup_cost,
|
subpath->startup_cost,
|
||||||
subpath->total_cost,
|
subpath->total_cost,
|
||||||
subpath->rows,
|
subpath->rows,
|
||||||
|
@ -3333,7 +3427,7 @@ create_groupingsets_path(PlannerInfo *root,
|
||||||
numGroupCols,
|
numGroupCols,
|
||||||
rollup->numGroups,
|
rollup->numGroups,
|
||||||
having_qual,
|
having_qual,
|
||||||
0.0, 0.0,
|
0, 0.0, 0.0,
|
||||||
subpath->rows,
|
subpath->rows,
|
||||||
subpath->pathtarget->width);
|
subpath->pathtarget->width);
|
||||||
if (!rollup->is_hashed)
|
if (!rollup->is_hashed)
|
||||||
|
@ -3342,7 +3436,7 @@ create_groupingsets_path(PlannerInfo *root,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Account for cost of sort, but don't charge input cost again */
|
/* Account for cost of sort, but don't charge input cost again */
|
||||||
cost_sort(&sort_path, root, NIL,
|
cost_sort(&sort_path, root, NIL, 0,
|
||||||
0.0,
|
0.0,
|
||||||
subpath->rows,
|
subpath->rows,
|
||||||
subpath->pathtarget->width,
|
subpath->pathtarget->width,
|
||||||
|
@ -3358,12 +3452,14 @@ create_groupingsets_path(PlannerInfo *root,
|
||||||
numGroupCols,
|
numGroupCols,
|
||||||
rollup->numGroups,
|
rollup->numGroups,
|
||||||
having_qual,
|
having_qual,
|
||||||
|
sort_path.disabled_nodes,
|
||||||
sort_path.startup_cost,
|
sort_path.startup_cost,
|
||||||
sort_path.total_cost,
|
sort_path.total_cost,
|
||||||
sort_path.rows,
|
sort_path.rows,
|
||||||
subpath->pathtarget->width);
|
subpath->pathtarget->width);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pathnode->path.disabled_nodes += agg_path.disabled_nodes;
|
||||||
pathnode->path.total_cost += agg_path.total_cost;
|
pathnode->path.total_cost += agg_path.total_cost;
|
||||||
pathnode->path.rows += agg_path.rows;
|
pathnode->path.rows += agg_path.rows;
|
||||||
}
|
}
|
||||||
|
@ -3395,6 +3491,7 @@ create_minmaxagg_path(PlannerInfo *root,
|
||||||
{
|
{
|
||||||
MinMaxAggPath *pathnode = makeNode(MinMaxAggPath);
|
MinMaxAggPath *pathnode = makeNode(MinMaxAggPath);
|
||||||
Cost initplan_cost;
|
Cost initplan_cost;
|
||||||
|
int initplan_disabled_nodes = 0;
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
|
||||||
/* The topmost generated Plan node will be a Result */
|
/* The topmost generated Plan node will be a Result */
|
||||||
|
@ -3419,12 +3516,14 @@ create_minmaxagg_path(PlannerInfo *root,
|
||||||
{
|
{
|
||||||
MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
|
MinMaxAggInfo *mminfo = (MinMaxAggInfo *) lfirst(lc);
|
||||||
|
|
||||||
|
initplan_disabled_nodes += mminfo->path->disabled_nodes;
|
||||||
initplan_cost += mminfo->pathcost;
|
initplan_cost += mminfo->pathcost;
|
||||||
if (!mminfo->path->parallel_safe)
|
if (!mminfo->path->parallel_safe)
|
||||||
pathnode->path.parallel_safe = false;
|
pathnode->path.parallel_safe = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* add tlist eval cost for each output row, plus cpu_tuple_cost */
|
/* add tlist eval cost for each output row, plus cpu_tuple_cost */
|
||||||
|
pathnode->path.disabled_nodes = initplan_disabled_nodes;
|
||||||
pathnode->path.startup_cost = initplan_cost + target->cost.startup;
|
pathnode->path.startup_cost = initplan_cost + target->cost.startup;
|
||||||
pathnode->path.total_cost = initplan_cost + target->cost.startup +
|
pathnode->path.total_cost = initplan_cost + target->cost.startup +
|
||||||
target->cost.per_tuple + cpu_tuple_cost;
|
target->cost.per_tuple + cpu_tuple_cost;
|
||||||
|
@ -3517,6 +3616,7 @@ create_windowagg_path(PlannerInfo *root,
|
||||||
cost_windowagg(&pathnode->path, root,
|
cost_windowagg(&pathnode->path, root,
|
||||||
windowFuncs,
|
windowFuncs,
|
||||||
winclause,
|
winclause,
|
||||||
|
subpath->disabled_nodes,
|
||||||
subpath->startup_cost,
|
subpath->startup_cost,
|
||||||
subpath->total_cost,
|
subpath->total_cost,
|
||||||
subpath->rows);
|
subpath->rows);
|
||||||
|
@ -3584,6 +3684,7 @@ create_setop_path(PlannerInfo *root,
|
||||||
* Charge one cpu_operator_cost per comparison per input tuple. We assume
|
* Charge one cpu_operator_cost per comparison per input tuple. We assume
|
||||||
* all columns get compared at most of the tuples.
|
* all columns get compared at most of the tuples.
|
||||||
*/
|
*/
|
||||||
|
pathnode->path.disabled_nodes = subpath->disabled_nodes;
|
||||||
pathnode->path.startup_cost = subpath->startup_cost;
|
pathnode->path.startup_cost = subpath->startup_cost;
|
||||||
pathnode->path.total_cost = subpath->total_cost +
|
pathnode->path.total_cost = subpath->total_cost +
|
||||||
cpu_operator_cost * subpath->rows * list_length(distinctList);
|
cpu_operator_cost * subpath->rows * list_length(distinctList);
|
||||||
|
@ -3683,6 +3784,7 @@ create_lockrows_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
* possible refetches, but it's hard to say how much. For now, use
|
* possible refetches, but it's hard to say how much. For now, use
|
||||||
* cpu_tuple_cost per row.
|
* cpu_tuple_cost per row.
|
||||||
*/
|
*/
|
||||||
|
pathnode->path.disabled_nodes = subpath->disabled_nodes;
|
||||||
pathnode->path.startup_cost = subpath->startup_cost;
|
pathnode->path.startup_cost = subpath->startup_cost;
|
||||||
pathnode->path.total_cost = subpath->total_cost +
|
pathnode->path.total_cost = subpath->total_cost +
|
||||||
cpu_tuple_cost * subpath->rows;
|
cpu_tuple_cost * subpath->rows;
|
||||||
|
@ -3759,6 +3861,7 @@ create_modifytable_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
* costs to change any higher-level planning choices. But we might want
|
* costs to change any higher-level planning choices. But we might want
|
||||||
* to make it look better sometime.
|
* to make it look better sometime.
|
||||||
*/
|
*/
|
||||||
|
pathnode->path.disabled_nodes = subpath->disabled_nodes;
|
||||||
pathnode->path.startup_cost = subpath->startup_cost;
|
pathnode->path.startup_cost = subpath->startup_cost;
|
||||||
pathnode->path.total_cost = subpath->total_cost;
|
pathnode->path.total_cost = subpath->total_cost;
|
||||||
if (returningLists != NIL)
|
if (returningLists != NIL)
|
||||||
|
@ -3835,6 +3938,7 @@ create_limit_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
subpath->parallel_safe;
|
subpath->parallel_safe;
|
||||||
pathnode->path.parallel_workers = subpath->parallel_workers;
|
pathnode->path.parallel_workers = subpath->parallel_workers;
|
||||||
pathnode->path.rows = subpath->rows;
|
pathnode->path.rows = subpath->rows;
|
||||||
|
pathnode->path.disabled_nodes = subpath->disabled_nodes;
|
||||||
pathnode->path.startup_cost = subpath->startup_cost;
|
pathnode->path.startup_cost = subpath->startup_cost;
|
||||||
pathnode->path.total_cost = subpath->total_cost;
|
pathnode->path.total_cost = subpath->total_cost;
|
||||||
pathnode->path.pathkeys = subpath->pathkeys;
|
pathnode->path.pathkeys = subpath->pathkeys;
|
||||||
|
|
|
@ -1658,6 +1658,7 @@ typedef struct Path
|
||||||
|
|
||||||
/* estimated size/costs for path (see costsize.c for more info) */
|
/* estimated size/costs for path (see costsize.c for more info) */
|
||||||
Cardinality rows; /* estimated number of result tuples */
|
Cardinality rows; /* estimated number of result tuples */
|
||||||
|
int disabled_nodes; /* count of disabled nodes */
|
||||||
Cost startup_cost; /* cost expended before fetching any tuples */
|
Cost startup_cost; /* cost expended before fetching any tuples */
|
||||||
Cost total_cost; /* total cost (assuming all tuples fetched) */
|
Cost total_cost; /* total cost (assuming all tuples fetched) */
|
||||||
|
|
||||||
|
@ -3333,6 +3334,7 @@ typedef struct
|
||||||
typedef struct JoinCostWorkspace
|
typedef struct JoinCostWorkspace
|
||||||
{
|
{
|
||||||
/* Preliminary cost estimates --- must not be larger than final ones! */
|
/* Preliminary cost estimates --- must not be larger than final ones! */
|
||||||
|
int disabled_nodes;
|
||||||
Cost startup_cost; /* cost expended before fetching any tuples */
|
Cost startup_cost; /* cost expended before fetching any tuples */
|
||||||
Cost total_cost; /* total cost (assuming all tuples fetched) */
|
Cost total_cost; /* total cost (assuming all tuples fetched) */
|
||||||
|
|
||||||
|
|
|
@ -108,35 +108,42 @@ extern void cost_resultscan(Path *path, PlannerInfo *root,
|
||||||
RelOptInfo *baserel, ParamPathInfo *param_info);
|
RelOptInfo *baserel, ParamPathInfo *param_info);
|
||||||
extern void cost_recursive_union(Path *runion, Path *nrterm, Path *rterm);
|
extern void cost_recursive_union(Path *runion, Path *nrterm, Path *rterm);
|
||||||
extern void cost_sort(Path *path, PlannerInfo *root,
|
extern void cost_sort(Path *path, PlannerInfo *root,
|
||||||
List *pathkeys, Cost input_cost, double tuples, int width,
|
List *pathkeys, int disabled_nodes,
|
||||||
|
Cost input_cost, double tuples, int width,
|
||||||
Cost comparison_cost, int sort_mem,
|
Cost comparison_cost, int sort_mem,
|
||||||
double limit_tuples);
|
double limit_tuples);
|
||||||
extern void cost_incremental_sort(Path *path,
|
extern void cost_incremental_sort(Path *path,
|
||||||
PlannerInfo *root, List *pathkeys, int presorted_keys,
|
PlannerInfo *root, List *pathkeys, int presorted_keys,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double input_tuples, int width, Cost comparison_cost, int sort_mem,
|
double input_tuples, int width, Cost comparison_cost, int sort_mem,
|
||||||
double limit_tuples);
|
double limit_tuples);
|
||||||
extern void cost_append(AppendPath *apath);
|
extern void cost_append(AppendPath *apath);
|
||||||
extern void cost_merge_append(Path *path, PlannerInfo *root,
|
extern void cost_merge_append(Path *path, PlannerInfo *root,
|
||||||
List *pathkeys, int n_streams,
|
List *pathkeys, int n_streams,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double tuples);
|
double tuples);
|
||||||
extern void cost_material(Path *path,
|
extern void cost_material(Path *path,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double tuples, int width);
|
double tuples, int width);
|
||||||
extern void cost_agg(Path *path, PlannerInfo *root,
|
extern void cost_agg(Path *path, PlannerInfo *root,
|
||||||
AggStrategy aggstrategy, const AggClauseCosts *aggcosts,
|
AggStrategy aggstrategy, const AggClauseCosts *aggcosts,
|
||||||
int numGroupCols, double numGroups,
|
int numGroupCols, double numGroups,
|
||||||
List *quals,
|
List *quals,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double input_tuples, double input_width);
|
double input_tuples, double input_width);
|
||||||
extern void cost_windowagg(Path *path, PlannerInfo *root,
|
extern void cost_windowagg(Path *path, PlannerInfo *root,
|
||||||
List *windowFuncs, WindowClause *winclause,
|
List *windowFuncs, WindowClause *winclause,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double input_tuples);
|
double input_tuples);
|
||||||
extern void cost_group(Path *path, PlannerInfo *root,
|
extern void cost_group(Path *path, PlannerInfo *root,
|
||||||
int numGroupCols, double numGroups,
|
int numGroupCols, double numGroups,
|
||||||
List *quals,
|
List *quals,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double input_tuples);
|
double input_tuples);
|
||||||
extern void initial_cost_nestloop(PlannerInfo *root,
|
extern void initial_cost_nestloop(PlannerInfo *root,
|
||||||
|
@ -171,6 +178,7 @@ extern void cost_gather(GatherPath *path, PlannerInfo *root,
|
||||||
RelOptInfo *rel, ParamPathInfo *param_info, double *rows);
|
RelOptInfo *rel, ParamPathInfo *param_info, double *rows);
|
||||||
extern void cost_gather_merge(GatherMergePath *path, PlannerInfo *root,
|
extern void cost_gather_merge(GatherMergePath *path, PlannerInfo *root,
|
||||||
RelOptInfo *rel, ParamPathInfo *param_info,
|
RelOptInfo *rel, ParamPathInfo *param_info,
|
||||||
|
int input_disabled_nodes,
|
||||||
Cost input_startup_cost, Cost input_total_cost,
|
Cost input_startup_cost, Cost input_total_cost,
|
||||||
double *rows);
|
double *rows);
|
||||||
extern void cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan);
|
extern void cost_subplan(PlannerInfo *root, SubPlan *subplan, Plan *plan);
|
||||||
|
|
|
@ -27,11 +27,12 @@ extern int compare_fractional_path_costs(Path *path1, Path *path2,
|
||||||
double fraction);
|
double fraction);
|
||||||
extern void set_cheapest(RelOptInfo *parent_rel);
|
extern void set_cheapest(RelOptInfo *parent_rel);
|
||||||
extern void add_path(RelOptInfo *parent_rel, Path *new_path);
|
extern void add_path(RelOptInfo *parent_rel, Path *new_path);
|
||||||
extern bool add_path_precheck(RelOptInfo *parent_rel,
|
extern bool add_path_precheck(RelOptInfo *parent_rel, int disabled_nodes,
|
||||||
Cost startup_cost, Cost total_cost,
|
Cost startup_cost, Cost total_cost,
|
||||||
List *pathkeys, Relids required_outer);
|
List *pathkeys, Relids required_outer);
|
||||||
extern void add_partial_path(RelOptInfo *parent_rel, Path *new_path);
|
extern void add_partial_path(RelOptInfo *parent_rel, Path *new_path);
|
||||||
extern bool add_partial_path_precheck(RelOptInfo *parent_rel,
|
extern bool add_partial_path_precheck(RelOptInfo *parent_rel,
|
||||||
|
int disabled_nodes,
|
||||||
Cost total_cost, List *pathkeys);
|
Cost total_cost, List *pathkeys);
|
||||||
|
|
||||||
extern Path *create_seqscan_path(PlannerInfo *root, RelOptInfo *rel,
|
extern Path *create_seqscan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
|
@ -124,7 +125,8 @@ extern Path *create_worktablescan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
Relids required_outer);
|
Relids required_outer);
|
||||||
extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
double rows, Cost startup_cost, Cost total_cost,
|
double rows, int disabled_nodes,
|
||||||
|
Cost startup_cost, Cost total_cost,
|
||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Relids required_outer,
|
Relids required_outer,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
|
@ -132,7 +134,8 @@ extern ForeignPath *create_foreignscan_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
List *fdw_private);
|
List *fdw_private);
|
||||||
extern ForeignPath *create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
extern ForeignPath *create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
double rows, Cost startup_cost, Cost total_cost,
|
double rows, int disabled_nodes,
|
||||||
|
Cost startup_cost, Cost total_cost,
|
||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Relids required_outer,
|
Relids required_outer,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
|
@ -140,7 +143,8 @@ extern ForeignPath *create_foreign_join_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
List *fdw_private);
|
List *fdw_private);
|
||||||
extern ForeignPath *create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
|
extern ForeignPath *create_foreign_upper_path(PlannerInfo *root, RelOptInfo *rel,
|
||||||
PathTarget *target,
|
PathTarget *target,
|
||||||
double rows, Cost startup_cost, Cost total_cost,
|
double rows, int disabled_nodes,
|
||||||
|
Cost startup_cost, Cost total_cost,
|
||||||
List *pathkeys,
|
List *pathkeys,
|
||||||
Path *fdw_outerpath,
|
Path *fdw_outerpath,
|
||||||
List *fdw_restrictinfo,
|
List *fdw_restrictinfo,
|
||||||
|
|
|
@ -40,7 +40,6 @@ session pruner
|
||||||
setup
|
setup
|
||||||
{
|
{
|
||||||
SET enable_seqscan = false;
|
SET enable_seqscan = false;
|
||||||
SET enable_indexscan = false;
|
|
||||||
SET enable_bitmapscan = false;
|
SET enable_bitmapscan = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -333,10 +333,12 @@ select proname from pg_proc where proname ilike '00%foo' order by 1;
|
||||||
explain (costs off)
|
explain (costs off)
|
||||||
select proname from pg_proc where proname ilike 'ri%foo' order by 1;
|
select proname from pg_proc where proname ilike 'ri%foo' order by 1;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
-----------------------------------------------------------------
|
----------------------------------------------
|
||||||
Index Only Scan using pg_proc_proname_args_nsp_index on pg_proc
|
Sort
|
||||||
|
Sort Key: proname
|
||||||
|
-> Seq Scan on pg_proc
|
||||||
Filter: (proname ~~* 'ri%foo'::text)
|
Filter: (proname ~~* 'ri%foo'::text)
|
||||||
(2 rows)
|
(4 rows)
|
||||||
|
|
||||||
reset enable_seqscan;
|
reset enable_seqscan;
|
||||||
reset enable_indexscan;
|
reset enable_indexscan;
|
||||||
|
|
|
@ -538,7 +538,9 @@ explain (costs off)
|
||||||
------------------------------------------------------------
|
------------------------------------------------------------
|
||||||
Aggregate
|
Aggregate
|
||||||
-> Nested Loop
|
-> Nested Loop
|
||||||
-> Seq Scan on tenk2
|
-> Gather
|
||||||
|
Workers Planned: 4
|
||||||
|
-> Parallel Seq Scan on tenk2
|
||||||
Filter: (thousand = 0)
|
Filter: (thousand = 0)
|
||||||
-> Gather
|
-> Gather
|
||||||
Workers Planned: 4
|
Workers Planned: 4
|
||||||
|
@ -546,7 +548,7 @@ explain (costs off)
|
||||||
Recheck Cond: (hundred > 1)
|
Recheck Cond: (hundred > 1)
|
||||||
-> Bitmap Index Scan on tenk1_hundred
|
-> Bitmap Index Scan on tenk1_hundred
|
||||||
Index Cond: (hundred > 1)
|
Index Cond: (hundred > 1)
|
||||||
(10 rows)
|
(12 rows)
|
||||||
|
|
||||||
select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0;
|
select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0;
|
||||||
count
|
count
|
||||||
|
|
Loading…
Reference in New Issue