diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index ce32b8a4..c0bf602 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -1742,6 +1742,33 @@ cost_sort(Path *path, PlannerInfo *root, } /* + * cost_append + * Determines and returns the cost of an Append node. + * + * Though Append doesn't do any selection or projection, it's not free. So we + * try to add cost per input tuple which is arbitrarily calculated as + * DEFAULT_APPEND_COST_FACTOR * cpu_tuple_cost. + * + * 'input_startup_cost' is the sum of the input streams' startup costs + * 'input_total_cost' is the sum of the input streams' total costs + * 'tuples' is the number of tuples in all the streams + */ +void +cost_append(Path *path, + Cost input_startup_cost, Cost input_total_cost, + double tuples) +{ + Cost startup_cost = 0; + Cost run_cost = 0; + + /* Add Append node overhead. */ + run_cost += cpu_tuple_cost * DEFAULT_APPEND_COST_FACTOR * tuples; + + path->startup_cost = startup_cost + input_startup_cost; + path->total_cost = startup_cost + run_cost + input_total_cost; +} + +/* * cost_merge_append * Determines and returns the cost of a MergeAppend node. * @@ -1800,6 +1827,9 @@ cost_merge_append(Path *path, PlannerInfo *root, */ run_cost += cpu_operator_cost * tuples; + /* Add MergeAppend node overhead like we do it for the Append node */ + run_cost += cpu_tuple_cost * DEFAULT_APPEND_COST_FACTOR * tuples; + path->startup_cost = startup_cost + input_startup_cost; path->total_cost = startup_cost + run_cost + input_total_cost; } diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c index 2d491eb..c8fdf1c 100644 --- a/src/backend/optimizer/util/pathnode.c +++ b/src/backend/optimizer/util/pathnode.c @@ -1212,6 +1212,8 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer, int parallel_workers, List *partitioned_rels) { AppendPath *pathnode = makeNode(AppendPath); + Cost input_startup_cost; + Cost input_total_cost; ListCell *l; pathnode->path.pathtype = T_Append; @@ -1227,32 +1229,31 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer, pathnode->subpaths = subpaths; /* - * We don't bother with inventing a cost_append(), but just do it here. - * - * Compute rows and costs as sums of subplan rows and costs. We charge - * nothing extra for the Append itself, which perhaps is too optimistic, - * but since it doesn't do any selection or projection, it is a pretty - * cheap node. + * Add up the sizes and costs of the input paths. */ pathnode->path.rows = 0; - pathnode->path.startup_cost = 0; - pathnode->path.total_cost = 0; + input_startup_cost = 0; + input_total_cost = 0; foreach(l, subpaths) { Path *subpath = (Path *) lfirst(l); pathnode->path.rows += subpath->rows; - - if (l == list_head(subpaths)) /* first node? */ - pathnode->path.startup_cost = subpath->startup_cost; - pathnode->path.total_cost += subpath->total_cost; pathnode->path.parallel_safe = pathnode->path.parallel_safe && subpath->parallel_safe; + if (l == list_head(subpaths)) /* first node? */ + input_startup_cost = subpath->startup_cost; + input_total_cost += subpath->total_cost; + /* All child paths must have same parameterization */ Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer)); } + /* Now we can compute total costs of the Append */ + cost_append(&pathnode->path, input_startup_cost, input_total_cost, + pathnode->path.rows); + return pathnode; } diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index 306d923..cd42e5a 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -31,6 +31,12 @@ #define DEFAULT_EFFECTIVE_CACHE_SIZE 524288 /* measured in pages */ +/* + * Arbitrarily use 50% of the cpu_tuple_cost to cost append node. Note that + * this value should be multiplied with cpu_tuple_cost wherever applicable. + */ +#define DEFAULT_APPEND_COST_FACTOR 0.5 + typedef enum { CONSTRAINT_EXCLUSION_OFF, /* do not use c_e */ @@ -106,6 +112,9 @@ extern void cost_sort(Path *path, PlannerInfo *root, List *pathkeys, Cost input_cost, double tuples, int width, Cost comparison_cost, int sort_mem, double limit_tuples); +extern void cost_append(Path *path, + Cost input_startup_cost, Cost input_total_cost, + double tuples); extern void cost_merge_append(Path *path, PlannerInfo *root, List *pathkeys, int n_streams, Cost input_startup_cost, Cost input_total_cost,