aboutsummaryrefslogtreecommitdiff
path: root/src/backend/optimizer/plan/planner.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r--src/backend/optimizer/plan/planner.c201
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,