diff options
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 201 |
1 files changed, 77 insertions, 124 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 2e2458b1284..01fa45b9255 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -5102,8 +5102,9 @@ create_ordered_paths(PlannerInfo *root, * have generated order-preserving Gather Merge plans which can be used * without sorting if they happen to match the sort_pathkeys, and the loop * above will have handled those as well. However, there's one more - * possibility: it may make sense to sort the cheapest partial path - * according to the required output order and then use Gather Merge. + * possibility: it may make sense to sort the cheapest partial path or + * incrementally sort any partial path that is partially sorted according + * to the required output order and then use Gather Merge. */ if (ordered_rel->consider_parallel && root->sort_pathkeys != NIL && input_rel->partial_pathlist != NIL) @@ -5112,97 +5113,65 @@ 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); - } - - /* - * 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; - - /* - * 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). - */ - - is_sorted = pathkeys_count_contained_in(root->sort_pathkeys, - input_path->pathkeys, - &presorted_keys); + is_sorted = pathkeys_count_contained_in(root->sort_pathkeys, + input_path->pathkeys, + &presorted_keys); - /* No point in adding incremental sort on fully sorted paths. */ - if (is_sorted) - continue; + if (is_sorted) + continue; - if (presorted_keys == 0) - continue; + /* + * 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 + * partial path). + */ + if (input_path != cheapest_partial_path && + (presorted_keys == 0 || !enable_incremental_sort)) + continue; - /* Since we have presorted keys, consider incremental sort. */ + /* + * 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); + 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); } } @@ -7322,44 +7291,9 @@ gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel) /* Try Gather for unordered paths and Gather Merge for ordered ones. */ generate_useful_gather_paths(root, rel, true); - /* Try cheapest partial path + explicit Sort + Gather Merge. */ cheapest_partial_path = linitial(rel->partial_pathlist); - if (!pathkeys_contained_in(root->group_pathkeys, - cheapest_partial_path->pathkeys)) - { - Path *path; - double total_groups; - - total_groups = - cheapest_partial_path->rows * cheapest_partial_path->parallel_workers; - path = (Path *) create_sort_path(root, rel, cheapest_partial_path, - root->group_pathkeys, - -1.0); - path = (Path *) - create_gather_merge_path(root, - rel, - path, - rel->reltarget, - root->group_pathkeys, - NULL, - &total_groups); - add_path(rel, path); - } - - /* - * Consider incremental sort on all partial paths, if enabled. - * - * We can also skip the entire loop when we only have a single-item - * group_pathkeys because then we can't possibly have a presorted prefix - * of the list without having the list be fully sorted. - * - * XXX Shouldn't this also consider the group-key-reordering? - */ - if (!enable_incremental_sort || list_length(root->group_pathkeys) == 1) - return; - - /* also consider incremental sort on partial paths, if enabled */ + /* XXX Shouldn't this also consider the group-key-reordering? */ foreach(lc, rel->partial_pathlist) { Path *path = (Path *) lfirst(lc); @@ -7374,15 +7308,34 @@ gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel) if (is_sorted) continue; - if (presorted_keys == 0) + /* + * 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 (path != cheapest_partial_path && + (presorted_keys == 0 || !enable_incremental_sort)) continue; - path = (Path *) create_incremental_sort_path(root, - rel, - path, - root->group_pathkeys, - presorted_keys, - -1.0); + total_groups = path->rows * path->parallel_workers; + + /* + * 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) + path = (Path *) create_sort_path(root, rel, path, + root->group_pathkeys, + -1.0); + else + path = (Path *) create_incremental_sort_path(root, + rel, + path, + root->group_pathkeys, + presorted_keys, + -1.0); path = (Path *) create_gather_merge_path(root, |