diff options
| author | Richard Guo <rguo@postgresql.org> | 2025-11-05 18:10:54 +0900 |
|---|---|---|
| committer | Richard Guo <rguo@postgresql.org> | 2025-11-05 18:10:54 +0900 |
| commit | 0ea5eee37606386150aa8317184617e1d5d34565 (patch) | |
| tree | 4a4a11595db2e554055c55ab104729a6e926ef68 | |
| parent | c1777f2d6d43adf9bc65da3e44a3a5ad2cbfa86d (diff) | |
Avoid creating duplicate ordered append paths
In generate_orderedappend_paths(), the function does not handle the
case where the paths in total_subpaths and fractional_subpaths are
identical. This situation is not uncommon, and as a result, it may
generate two exactly identical ordered append paths.
Fix by checking whether total_subpaths and fractional_subpaths contain
the same paths, and skipping creation of the ordered append path for
the fractional case when they are identical.
Given the lack of field complaints about this, I'm a bit hesitant to
back-patch, but let's clean it up in HEAD.
Author: Richard Guo <guofenglinux@gmail.com>
Reviewed-by: Andrei Lepikhov <lepihov@gmail.com>
Reviewed-by: Alexander Korotkov <aekorotkov@gmail.com>
Discussion: https://postgr.es/m/CAMbWs4-OYsgA75tGGiBARt87G0y_z_GBTSLrzudcJxAzndYkYw@mail.gmail.com
| -rw-r--r-- | src/backend/optimizer/path/allpaths.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 41233b98373..4c43fd0b19b 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1877,6 +1877,7 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, List *total_subpaths = NIL; List *fractional_subpaths = NIL; bool startup_neq_total = false; + bool fraction_neq_total = false; bool match_partition_order; bool match_partition_order_desc; int end_index; @@ -2005,15 +2006,21 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, * XXX We might consider partially sorted paths too (with an * incremental sort on top). But we'd have to build all the * incremental paths, do the costing etc. + * + * Also, notice whether we actually have different paths for + * the "fractional" and "total" cases. This helps avoid + * generating two identical ordered append paths. */ - if (!cheapest_fractional) + if (cheapest_fractional == NULL) cheapest_fractional = cheapest_total; + else if (cheapest_fractional != cheapest_total) + fraction_neq_total = true; } /* * Notice whether we actually have different paths for the - * "cheapest" and "total" cases; frequently there will be no point - * in two create_merge_append_path() calls. + * "cheapest" and "total" cases. This helps avoid generating two + * identical ordered append paths. */ if (cheapest_startup != cheapest_total) startup_neq_total = true; @@ -2084,7 +2091,7 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, false, -1)); - if (fractional_subpaths) + if (fractional_subpaths && fraction_neq_total) add_path(rel, (Path *) create_append_path(root, rel, fractional_subpaths, @@ -2110,7 +2117,7 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, pathkeys, NULL)); - if (fractional_subpaths) + if (fractional_subpaths && fraction_neq_total) add_path(rel, (Path *) create_merge_append_path(root, rel, fractional_subpaths, |
