aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/pathnode.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/util/pathnode.c')
-rw-r--r--src/backend/optimizer/util/pathnode.c42
1 files changed, 35 insertions, 7 deletions
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 169e51e7921..56de8fc370a 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1242,7 +1242,6 @@ create_append_path(PlannerInfo *root,
pathnode->path.parallel_aware = parallel_aware;
pathnode->path.parallel_safe = rel->consider_parallel;
pathnode->path.parallel_workers = parallel_workers;
- pathnode->path.pathkeys = NIL; /* result is always considered unsorted */
pathnode->partitioned_rels = list_copy(partitioned_rels);
/*
@@ -1276,7 +1275,26 @@ create_append_path(PlannerInfo *root,
Assert(!parallel_aware || pathnode->path.parallel_safe);
- cost_append(pathnode);
+ /*
+ * If there's exactly one child path, the Append is a no-op and will be
+ * discarded later (in setrefs.c); therefore, we can inherit the child's
+ * size, cost, and pathkeys if any. Otherwise, it's unsorted, and we must
+ * do the normal costsize calculation.
+ */
+ if (list_length(pathnode->subpaths) == 1)
+ {
+ Path *child = (Path *) linitial(pathnode->subpaths);
+
+ pathnode->path.rows = child->rows;
+ pathnode->path.startup_cost = child->startup_cost;
+ pathnode->path.total_cost = child->total_cost;
+ pathnode->path.pathkeys = child->pathkeys;
+ }
+ else
+ {
+ pathnode->path.pathkeys = NIL; /* unsorted if more than 1 subpath */
+ cost_append(pathnode);
+ }
/* If the caller provided a row estimate, override the computed value. */
if (rows >= 0)
@@ -1408,11 +1426,21 @@ create_merge_append_path(PlannerInfo *root,
Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer));
}
- /* Now we can compute total costs of the MergeAppend */
- cost_merge_append(&pathnode->path, root,
- pathkeys, list_length(subpaths),
- input_startup_cost, input_total_cost,
- pathnode->path.rows);
+ /*
+ * Now we can compute total costs of the MergeAppend. If there's exactly
+ * one child path, the MergeAppend is a no-op and will be discarded later
+ * (in setrefs.c); otherwise we do the normal cost calculation.
+ */
+ if (list_length(subpaths) == 1)
+ {
+ pathnode->path.startup_cost = input_startup_cost;
+ pathnode->path.total_cost = input_total_cost;
+ }
+ else
+ cost_merge_append(&pathnode->path, root,
+ pathkeys, list_length(subpaths),
+ input_startup_cost, input_total_cost,
+ pathnode->path.rows);
return pathnode;
}