From 744c94b9be05a4195a167bb9360e2f8769dd524f Mon Sep 17 00:00:00 2001 From: Richard Guo Date: Tue, 10 Jan 2023 16:40:39 +0800 Subject: [PATCH v1 2/3] Revise how we sort partial paths in create_ordered_paths --- src/backend/optimizer/plan/planner.c | 124 +++++++++++---------------- 1 file changed, 48 insertions(+), 76 deletions(-) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 000d757bdd..9f22bcbf1a 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -5045,97 +5045,69 @@ create_ordered_paths(PlannerInfo *root, cheapest_partial_path = linitial(input_rel->partial_pathlist); - /* - * If cheapest partial path doesn't need a sort, this is redundant - * with what's already been tried. - */ - if (!pathkeys_contained_in(root->sort_pathkeys, - cheapest_partial_path->pathkeys)) + foreach(lc, input_rel->partial_pathlist) { - Path *path; + Path *input_path = (Path *) lfirst(lc); + Path *sorted_path; + bool is_sorted; + int presorted_keys; double total_groups; - path = (Path *) create_sort_path(root, - ordered_rel, - cheapest_partial_path, - root->sort_pathkeys, - limit_tuples); - - total_groups = cheapest_partial_path->rows * - cheapest_partial_path->parallel_workers; - path = (Path *) - create_gather_merge_path(root, ordered_rel, - path, - path->pathtarget, - root->sort_pathkeys, NULL, - &total_groups); - - /* Add projection step if needed */ - if (path->pathtarget != target) - path = apply_projection_to_path(root, ordered_rel, - path, target); - - add_path(ordered_rel, path); - } + is_sorted = pathkeys_count_contained_in(root->sort_pathkeys, + input_path->pathkeys, + &presorted_keys); - /* - * Consider incremental sort with a gather merge on partial paths. - * - * We can also skip the entire loop when we only have a single-item - * sort_pathkeys because then we can't possibly have a presorted - * prefix of the list without having the list be fully sorted. - */ - if (enable_incremental_sort && list_length(root->sort_pathkeys) > 1) - { - foreach(lc, input_rel->partial_pathlist) - { - Path *input_path = (Path *) lfirst(lc); - Path *sorted_path; - bool is_sorted; - int presorted_keys; - double total_groups; + /* No point in adding incremental sort on fully sorted paths. */ + if (is_sorted) + continue; - /* - * We don't care if this is the cheapest partial path - we - * can't simply skip it, because it may be partially sorted in - * which case we want to consider adding incremental sort - * (instead of full sort, which is what happens above). - */ + /* + * Try at least sorting the cheapest path and also try + * incrementally sorting any path which is partially sorted + * already (no need to deal with paths which have presorted + * keys when incremental sort is disabled unless it's the + * cheapest input path). + */ + if (input_path != cheapest_partial_path && + (presorted_keys == 0 || !enable_incremental_sort)) + continue; - is_sorted = pathkeys_count_contained_in(root->sort_pathkeys, - input_path->pathkeys, - &presorted_keys); + /* + * We've no need to consider both a sort and incremental sort. + * We'll just do a sort if there are no presorted keys and an + * incremental sort when there are presorted keys. + */ + if (presorted_keys == 0 || !enable_incremental_sort) + sorted_path = (Path *) create_sort_path(root, + ordered_rel, + input_path, + root->sort_pathkeys, + limit_tuples); - /* No point in adding incremental sort on fully sorted paths. */ - if (is_sorted) - continue; - if (presorted_keys == 0) - continue; - /* Since we have presorted keys, consider incremental sort. */ + else sorted_path = (Path *) create_incremental_sort_path(root, ordered_rel, input_path, root->sort_pathkeys, presorted_keys, limit_tuples); - total_groups = input_path->rows * - input_path->parallel_workers; - sorted_path = (Path *) - create_gather_merge_path(root, ordered_rel, - sorted_path, - sorted_path->pathtarget, - root->sort_pathkeys, NULL, - &total_groups); - - /* Add projection step if needed */ - if (sorted_path->pathtarget != target) - sorted_path = apply_projection_to_path(root, ordered_rel, - sorted_path, target); - - add_path(ordered_rel, sorted_path); - } + total_groups = input_path->rows * + input_path->parallel_workers; + sorted_path = (Path *) + create_gather_merge_path(root, ordered_rel, + sorted_path, + sorted_path->pathtarget, + root->sort_pathkeys, NULL, + &total_groups); + + /* Add projection step if needed */ + if (sorted_path->pathtarget != target) + sorted_path = apply_projection_to_path(root, ordered_rel, + sorted_path, target); + + add_path(ordered_rel, sorted_path); } } -- 2.31.0