diff options
author | Tomas Vondra | 2022-01-12 18:59:30 +0000 |
---|---|---|
committer | Tomas Vondra | 2022-01-12 21:27:24 +0000 |
commit | 6b94e7a6da2f1c6df1a42efe64251f32a444d174 (patch) | |
tree | 787346c6c0e4c4cb9997076b8d9da7380823dd8c /src/backend/optimizer | |
parent | 025b920a3d45fed441a0a58fdcdf05b321b1eead (diff) |
Consider fractional paths in generate_orderedappend_paths
When building append paths, we've been looking only at startup and total
costs for the paths. When building fractional paths that may eliminate
the cheapest one, because it may be dominated by two separate paths (one
for startup, one for total cost).
This extends generate_orderedappend_paths() to also consider which paths
have lowest fractional cost. Currently we only consider paths matching
pathkeys - in the future this may be improved by also considering paths
that are only partially sorted, with an incremental sort on top.
Original report of an issue by Arne Roland, patch by me (based on a
suggestion by Tom Lane).
Reviewed-by: Arne Roland, Zhihong Yu
Discussion: https://postgr.es/m/e8f9ec90-546d-e948-acce-0525f3e92773%40enterprisedb.com
Discussion: https://postgr.es/m/1581042da8044e71ada2d6e3a51bf7bb%40index.de
Diffstat (limited to 'src/backend/optimizer')
-rw-r--r-- | src/backend/optimizer/path/allpaths.c | 69 |
1 files changed, 68 insertions, 1 deletions
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index 056145ea44c..169b1d53fc8 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1716,6 +1716,7 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, List *pathkeys = (List *) lfirst(lcp); List *startup_subpaths = NIL; List *total_subpaths = NIL; + List *fractional_subpaths = NIL; bool startup_neq_total = false; ListCell *lcr; bool match_partition_order; @@ -1745,7 +1746,8 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, { RelOptInfo *childrel = (RelOptInfo *) lfirst(lcr); Path *cheapest_startup, - *cheapest_total; + *cheapest_total, + *cheapest_fractional = NULL; /* Locate the right paths, if they are available. */ cheapest_startup = @@ -1774,6 +1776,37 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, } /* + * When building a fractional path, determine a cheapest fractional + * path for each child relation too. Looking at startup and total + * costs is not enough, because the cheapest fractional path may be + * dominated by two separate paths (one for startup, one for total). + * + * When needed (building fractional path), determine the cheapest + * fractional path too. + */ + if (root->tuple_fraction > 0) + { + double path_fraction = (1.0 / root->tuple_fraction); + + cheapest_fractional = + get_cheapest_fractional_path_for_pathkeys(childrel->pathlist, + pathkeys, + NULL, + path_fraction); + + /* + * If we found no path with matching pathkeys, use the cheapest + * total path instead. + * + * 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. + */ + if (!cheapest_fractional) + cheapest_fractional = cheapest_total; + } + + /* * 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. @@ -1799,6 +1832,12 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, startup_subpaths = lappend(startup_subpaths, cheapest_startup); total_subpaths = lappend(total_subpaths, cheapest_total); + + if (cheapest_fractional) + { + cheapest_fractional = get_singleton_append_subpath(cheapest_fractional); + fractional_subpaths = lappend(fractional_subpaths, cheapest_fractional); + } } else if (match_partition_order_desc) { @@ -1812,6 +1851,12 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, startup_subpaths = lcons(cheapest_startup, startup_subpaths); total_subpaths = lcons(cheapest_total, total_subpaths); + + if (cheapest_fractional) + { + cheapest_fractional = get_singleton_append_subpath(cheapest_fractional); + fractional_subpaths = lcons(cheapest_fractional, fractional_subpaths); + } } else { @@ -1823,6 +1868,10 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, &startup_subpaths, NULL); accumulate_append_subpath(cheapest_total, &total_subpaths, NULL); + + if (cheapest_fractional) + accumulate_append_subpath(cheapest_fractional, + &fractional_subpaths, NULL); } } @@ -1849,6 +1898,17 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, 0, false, -1)); + + if (fractional_subpaths) + add_path(rel, (Path *) create_append_path(root, + rel, + fractional_subpaths, + NIL, + pathkeys, + NULL, + 0, + false, + -1)); } else { @@ -1864,6 +1924,13 @@ generate_orderedappend_paths(PlannerInfo *root, RelOptInfo *rel, total_subpaths, pathkeys, NULL)); + + if (fractional_subpaths) + add_path(rel, (Path *) create_merge_append_path(root, + rel, + fractional_subpaths, + pathkeys, + NULL)); } } } |