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.c654
1 files changed, 269 insertions, 385 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index d8e8f607b2b..468105d91ea 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -2756,9 +2756,8 @@ remove_useless_groupby_columns(PlannerInfo *root)
*
* In principle it might be interesting to consider other orderings of the
* GROUP BY elements, which could match the sort ordering of other
- * possible plans (eg an indexscan) and thereby reduce cost. However, we
- * don't yet have sufficient information to do that here, so that's left until
- * later in planning. See get_useful_group_keys_orderings().
+ * possible plans (eg an indexscan) and thereby reduce cost. We don't
+ * bother with that, though. Hashed grouping will frequently win anyway.
*
* Note: we need no comparable processing of the distinctClause because
* the parser already enforced that that matches ORDER BY.
@@ -6232,122 +6231,24 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
*/
foreach(lc, input_rel->pathlist)
{
- ListCell *lc2;
Path *path = (Path *) lfirst(lc);
Path *path_original = path;
+ bool is_sorted;
+ int presorted_keys;
- List *pathkey_orderings = NIL;
-
- List *group_pathkeys = root->group_pathkeys;
- List *group_clauses = parse->groupClause;
-
- /* generate alternative group orderings that might be useful */
- pathkey_orderings = get_useful_group_keys_orderings(root,
- path->rows,
- path->pathkeys,
- group_pathkeys,
- group_clauses);
+ is_sorted = pathkeys_count_contained_in(root->group_pathkeys,
+ path->pathkeys,
+ &presorted_keys);
- Assert(list_length(pathkey_orderings) > 0);
-
- /* process all potentially interesting grouping reorderings */
- foreach(lc2, pathkey_orderings)
+ if (path == cheapest_path || is_sorted)
{
- bool is_sorted;
- int presorted_keys = 0;
- PathKeyInfo *info = (PathKeyInfo *) lfirst(lc2);
-
- /* restore the path (we replace it in the loop) */
- path = path_original;
-
- is_sorted = pathkeys_count_contained_in(info->pathkeys,
- path->pathkeys,
- &presorted_keys);
-
- if (path == cheapest_path || is_sorted)
- {
- /* Sort the cheapest-total path if it isn't already sorted */
- if (!is_sorted)
- path = (Path *) create_sort_path(root,
- grouped_rel,
- path,
- info->pathkeys,
- -1.0);
-
- /* Now decide what to stick atop it */
- if (parse->groupingSets)
- {
- consider_groupingsets_paths(root, grouped_rel,
- path, true, can_hash,
- gd, agg_costs, dNumGroups);
- }
- else if (parse->hasAggs)
- {
- /*
- * We have aggregation, possibly with plain GROUP BY.
- * Make an AggPath.
- */
- add_path(grouped_rel, (Path *)
- create_agg_path(root,
- grouped_rel,
- path,
- grouped_rel->reltarget,
- info->clauses ? AGG_SORTED : AGG_PLAIN,
- AGGSPLIT_SIMPLE,
- info->clauses,
- havingQual,
- agg_costs,
- dNumGroups));
- }
- else if (group_clauses)
- {
- /*
- * We have GROUP BY without aggregation or grouping
- * sets. Make a GroupPath.
- */
- add_path(grouped_rel, (Path *)
- create_group_path(root,
- grouped_rel,
- path,
- info->clauses,
- havingQual,
- dNumGroups));
- }
- else
- {
- /* Other cases should have been handled above */
- Assert(false);
- }
- }
-
- /*
- * Now we may consider incremental sort on this path, but only
- * when the path is not already sorted and when incremental
- * sort is enabled.
- */
- if (is_sorted || !enable_incremental_sort)
- continue;
-
- /* Restore the input path (we might have added Sort on top). */
- path = path_original;
-
- /* no shared prefix, no point in building incremental sort */
- if (presorted_keys == 0)
- continue;
-
- /*
- * We should have already excluded pathkeys of length 1
- * because then presorted_keys > 0 would imply is_sorted was
- * true.
- */
- Assert(list_length(root->group_pathkeys) != 1);
-
- path = (Path *) create_incremental_sort_path(root,
- grouped_rel,
- path,
- info->pathkeys,
- presorted_keys,
- -1.0);
+ /* Sort the cheapest-total path if it isn't already sorted */
+ if (!is_sorted)
+ path = (Path *) create_sort_path(root,
+ grouped_rel,
+ path,
+ root->group_pathkeys,
+ -1.0);
/* Now decide what to stick atop it */
if (parse->groupingSets)
@@ -6367,9 +6268,9 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
grouped_rel,
path,
grouped_rel->reltarget,
- info->clauses ? AGG_SORTED : AGG_PLAIN,
+ parse->groupClause ? AGG_SORTED : AGG_PLAIN,
AGGSPLIT_SIMPLE,
- info->clauses,
+ parse->groupClause,
havingQual,
agg_costs,
dNumGroups));
@@ -6384,7 +6285,7 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
create_group_path(root,
grouped_rel,
path,
- info->clauses,
+ parse->groupClause,
havingQual,
dNumGroups));
}
@@ -6394,6 +6295,79 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
Assert(false);
}
}
+
+ /*
+ * Now we may consider incremental sort on this path, but only
+ * when the path is not already sorted and when incremental sort
+ * is enabled.
+ */
+ if (is_sorted || !enable_incremental_sort)
+ continue;
+
+ /* Restore the input path (we might have added Sort on top). */
+ path = path_original;
+
+ /* no shared prefix, no point in building incremental sort */
+ if (presorted_keys == 0)
+ continue;
+
+ /*
+ * We should have already excluded pathkeys of length 1 because
+ * then presorted_keys > 0 would imply is_sorted was true.
+ */
+ Assert(list_length(root->group_pathkeys) != 1);
+
+ path = (Path *) create_incremental_sort_path(root,
+ grouped_rel,
+ path,
+ root->group_pathkeys,
+ presorted_keys,
+ -1.0);
+
+ /* Now decide what to stick atop it */
+ if (parse->groupingSets)
+ {
+ consider_groupingsets_paths(root, grouped_rel,
+ path, true, can_hash,
+ gd, agg_costs, dNumGroups);
+ }
+ else if (parse->hasAggs)
+ {
+ /*
+ * We have aggregation, possibly with plain GROUP BY. Make an
+ * AggPath.
+ */
+ add_path(grouped_rel, (Path *)
+ create_agg_path(root,
+ grouped_rel,
+ path,
+ grouped_rel->reltarget,
+ parse->groupClause ? AGG_SORTED : AGG_PLAIN,
+ AGGSPLIT_SIMPLE,
+ parse->groupClause,
+ havingQual,
+ agg_costs,
+ dNumGroups));
+ }
+ else if (parse->groupClause)
+ {
+ /*
+ * We have GROUP BY without aggregation or grouping sets. Make
+ * a GroupPath.
+ */
+ add_path(grouped_rel, (Path *)
+ create_group_path(root,
+ grouped_rel,
+ path,
+ parse->groupClause,
+ havingQual,
+ dNumGroups));
+ }
+ else
+ {
+ /* Other cases should have been handled above */
+ Assert(false);
+ }
}
/*
@@ -6404,130 +6378,100 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
{
foreach(lc, partially_grouped_rel->pathlist)
{
- ListCell *lc2;
Path *path = (Path *) lfirst(lc);
Path *path_original = path;
+ bool is_sorted;
+ int presorted_keys;
- List *pathkey_orderings = NIL;
-
- List *group_pathkeys = root->group_pathkeys;
- List *group_clauses = parse->groupClause;
-
- /* generate alternative group orderings that might be useful */
- pathkey_orderings = get_useful_group_keys_orderings(root,
- path->rows,
- path->pathkeys,
- group_pathkeys,
- group_clauses);
-
- Assert(list_length(pathkey_orderings) > 0);
+ is_sorted = pathkeys_count_contained_in(root->group_pathkeys,
+ path->pathkeys,
+ &presorted_keys);
- /* process all potentially interesting grouping reorderings */
- foreach(lc2, pathkey_orderings)
+ /*
+ * Insert a Sort node, if required. But there's no point in
+ * sorting anything but the cheapest path.
+ */
+ if (!is_sorted)
{
- bool is_sorted;
- int presorted_keys = 0;
- PathKeyInfo *info = (PathKeyInfo *) lfirst(lc2);
-
- /* restore the path (we replace it in the loop) */
- path = path_original;
-
- is_sorted = pathkeys_count_contained_in(info->pathkeys,
- path->pathkeys,
- &presorted_keys);
-
- /*
- * Insert a Sort node, if required. But there's no point
- * in sorting anything but the cheapest path.
- */
- if (!is_sorted)
- {
- if (path != partially_grouped_rel->cheapest_total_path)
- continue;
- path = (Path *) create_sort_path(root,
- grouped_rel,
- path,
- info->pathkeys,
- -1.0);
- }
+ if (path != partially_grouped_rel->cheapest_total_path)
+ continue;
+ path = (Path *) create_sort_path(root,
+ grouped_rel,
+ path,
+ root->group_pathkeys,
+ -1.0);
+ }
- if (parse->hasAggs)
- add_path(grouped_rel, (Path *)
- create_agg_path(root,
- grouped_rel,
- path,
- grouped_rel->reltarget,
- info->clauses ? AGG_SORTED : AGG_PLAIN,
- AGGSPLIT_FINAL_DESERIAL,
- info->clauses,
- havingQual,
- agg_final_costs,
- dNumGroups));
- else
- add_path(grouped_rel, (Path *)
- create_group_path(root,
- grouped_rel,
- path,
- info->clauses,
- havingQual,
- dNumGroups));
+ if (parse->hasAggs)
+ add_path(grouped_rel, (Path *)
+ create_agg_path(root,
+ grouped_rel,
+ path,
+ grouped_rel->reltarget,
+ parse->groupClause ? AGG_SORTED : AGG_PLAIN,
+ AGGSPLIT_FINAL_DESERIAL,
+ parse->groupClause,
+ havingQual,
+ agg_final_costs,
+ dNumGroups));
+ else
+ add_path(grouped_rel, (Path *)
+ create_group_path(root,
+ grouped_rel,
+ path,
+ parse->groupClause,
+ havingQual,
+ dNumGroups));
- /*
- * Now we may consider incremental sort on this path, but
- * only when the path is not already sorted and when
- * incremental sort is enabled.
- */
- if (is_sorted || !enable_incremental_sort)
- continue;
+ /*
+ * Now we may consider incremental sort on this path, but only
+ * when the path is not already sorted and when incremental
+ * sort is enabled.
+ */
+ if (is_sorted || !enable_incremental_sort)
+ continue;
- /*
- * Restore the input path (we might have added Sort on
- * top).
- */
- path = path_original;
+ /* Restore the input path (we might have added Sort on top). */
+ path = path_original;
- /*
- * no shared prefix, not point in building incremental
- * sort
- */
- if (presorted_keys == 0)
- continue;
+ /* no shared prefix, not point in building incremental sort */
+ if (presorted_keys == 0)
+ continue;
- /*
- * We should have already excluded pathkeys of length 1
- * because then presorted_keys > 0 would imply is_sorted
- * was true.
- */
- Assert(list_length(root->group_pathkeys) != 1);
+ /*
+ * We should have already excluded pathkeys of length 1
+ * because then presorted_keys > 0 would imply is_sorted was
+ * true.
+ */
+ Assert(list_length(root->group_pathkeys) != 1);
- path = (Path *) create_incremental_sort_path(root,
- grouped_rel,
- path,
- info->pathkeys,
- presorted_keys,
- -1.0);
+ path = (Path *) create_incremental_sort_path(root,
+ grouped_rel,
+ path,
+ root->group_pathkeys,
+ presorted_keys,
+ -1.0);
- if (parse->hasAggs)
- add_path(grouped_rel, (Path *)
- create_agg_path(root,
- grouped_rel,
- path,
- grouped_rel->reltarget,
- info->clauses ? AGG_SORTED : AGG_PLAIN,
- AGGSPLIT_FINAL_DESERIAL,
- info->clauses,
- havingQual,
- agg_final_costs,
- dNumGroups));
- else
- add_path(grouped_rel, (Path *)
- create_group_path(root,
- grouped_rel,
- path,
- info->clauses,
- havingQual,
- dNumGroups));
- }
+ if (parse->hasAggs)
+ add_path(grouped_rel, (Path *)
+ create_agg_path(root,
+ grouped_rel,
+ path,
+ grouped_rel->reltarget,
+ parse->groupClause ? AGG_SORTED : AGG_PLAIN,
+ AGGSPLIT_FINAL_DESERIAL,
+ parse->groupClause,
+ havingQual,
+ agg_final_costs,
+ dNumGroups));
+ else
+ add_path(grouped_rel, (Path *)
+ create_group_path(root,
+ grouped_rel,
+ path,
+ parse->groupClause,
+ havingQual,
+ dNumGroups));
}
}
}
@@ -6730,71 +6674,41 @@ create_partial_grouping_paths(PlannerInfo *root,
*/
foreach(lc, input_rel->pathlist)
{
- ListCell *lc2;
Path *path = (Path *) lfirst(lc);
- Path *path_save = path;
-
- List *pathkey_orderings = NIL;
-
- List *group_pathkeys = root->group_pathkeys;
- List *group_clauses = parse->groupClause;
+ bool is_sorted;
- /* generate alternative group orderings that might be useful */
- pathkey_orderings = get_useful_group_keys_orderings(root,
- path->rows,
- path->pathkeys,
- group_pathkeys,
- group_clauses);
-
- Assert(list_length(pathkey_orderings) > 0);
-
- /* process all potentially interesting grouping reorderings */
- foreach(lc2, pathkey_orderings)
+ is_sorted = pathkeys_contained_in(root->group_pathkeys,
+ path->pathkeys);
+ if (path == cheapest_total_path || is_sorted)
{
- bool is_sorted;
- int presorted_keys = 0;
- PathKeyInfo *info = (PathKeyInfo *) lfirst(lc2);
-
- /* restore the path (we replace it in the loop) */
- path = path_save;
-
- is_sorted = pathkeys_count_contained_in(info->pathkeys,
- path->pathkeys,
- &presorted_keys);
-
- if (path == cheapest_total_path || is_sorted)
- {
- /* Sort the cheapest partial path, if it isn't already */
- if (!is_sorted)
- {
- path = (Path *) create_sort_path(root,
- partially_grouped_rel,
- path,
- info->pathkeys,
- -1.0);
- }
+ /* Sort the cheapest partial path, if it isn't already */
+ if (!is_sorted)
+ path = (Path *) create_sort_path(root,
+ partially_grouped_rel,
+ path,
+ root->group_pathkeys,
+ -1.0);
- if (parse->hasAggs)
- add_path(partially_grouped_rel, (Path *)
- create_agg_path(root,
- partially_grouped_rel,
- path,
- partially_grouped_rel->reltarget,
- info->clauses ? AGG_SORTED : AGG_PLAIN,
- AGGSPLIT_INITIAL_SERIAL,
- info->clauses,
- NIL,
- agg_partial_costs,
- dNumPartialGroups));
- else
- add_path(partially_grouped_rel, (Path *)
- create_group_path(root,
- partially_grouped_rel,
- path,
- info->clauses,
- NIL,
- dNumPartialGroups));
- }
+ if (parse->hasAggs)
+ add_path(partially_grouped_rel, (Path *)
+ create_agg_path(root,
+ partially_grouped_rel,
+ path,
+ partially_grouped_rel->reltarget,
+ parse->groupClause ? AGG_SORTED : AGG_PLAIN,
+ AGGSPLIT_INITIAL_SERIAL,
+ parse->groupClause,
+ NIL,
+ agg_partial_costs,
+ dNumPartialGroups));
+ else
+ add_path(partially_grouped_rel, (Path *)
+ create_group_path(root,
+ partially_grouped_rel,
+ path,
+ parse->groupClause,
+ NIL,
+ dNumPartialGroups));
}
}
@@ -6804,8 +6718,6 @@ create_partial_grouping_paths(PlannerInfo *root,
* 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)
{
@@ -6863,101 +6775,24 @@ create_partial_grouping_paths(PlannerInfo *root,
/* Similar to above logic, but for partial paths. */
foreach(lc, input_rel->partial_pathlist)
{
- ListCell *lc2;
Path *path = (Path *) lfirst(lc);
Path *path_original = path;
+ bool is_sorted;
+ int presorted_keys;
- List *pathkey_orderings = NIL;
-
- List *group_pathkeys = root->group_pathkeys;
- List *group_clauses = parse->groupClause;
+ is_sorted = pathkeys_count_contained_in(root->group_pathkeys,
+ path->pathkeys,
+ &presorted_keys);
- /* generate alternative group orderings that might be useful */
- pathkey_orderings = get_useful_group_keys_orderings(root,
- path->rows,
- path->pathkeys,
- group_pathkeys,
- group_clauses);
-
- Assert(list_length(pathkey_orderings) > 0);
-
- /* process all potentially interesting grouping reorderings */
- foreach(lc2, pathkey_orderings)
+ if (path == cheapest_partial_path || is_sorted)
{
- bool is_sorted;
- int presorted_keys = 0;
- PathKeyInfo *info = (PathKeyInfo *) lfirst(lc2);
-
- /* restore the path (we replace it in the loop) */
- path = path_original;
-
- is_sorted = pathkeys_count_contained_in(info->pathkeys,
- path->pathkeys,
- &presorted_keys);
-
- if (path == cheapest_partial_path || is_sorted)
- {
-
- /* Sort the cheapest partial path, if it isn't already */
- if (!is_sorted)
- {
- path = (Path *) create_sort_path(root,
- partially_grouped_rel,
- path,
- info->pathkeys,
- -1.0);
- }
-
- if (parse->hasAggs)
- add_partial_path(partially_grouped_rel, (Path *)
- create_agg_path(root,
- partially_grouped_rel,
- path,
- partially_grouped_rel->reltarget,
- info->clauses ? AGG_SORTED : AGG_PLAIN,
- AGGSPLIT_INITIAL_SERIAL,
- info->clauses,
- NIL,
- agg_partial_costs,
- dNumPartialPartialGroups));
- else
- add_partial_path(partially_grouped_rel, (Path *)
- create_group_path(root,
- partially_grouped_rel,
- path,
- info->clauses,
- NIL,
- dNumPartialPartialGroups));
- }
-
- /*
- * Now we may consider incremental sort on this path, but only
- * when the path is not already sorted and when incremental
- * sort is enabled.
- */
- if (is_sorted || !enable_incremental_sort)
- continue;
-
- /* Restore the input path (we might have added Sort on top). */
- path = path_original;
-
- /* no shared prefix, not point in building incremental sort */
- if (presorted_keys == 0)
- continue;
-
- /*
- * We should have already excluded pathkeys of length 1
- * because then presorted_keys > 0 would imply is_sorted was
- * true.
- */
- Assert(list_length(root->group_pathkeys) != 1);
-
- path = (Path *) create_incremental_sort_path(root,
- partially_grouped_rel,
- path,
- info->pathkeys,
- presorted_keys,
- -1.0);
+ /* Sort the cheapest partial path, if it isn't already */
+ if (!is_sorted)
+ path = (Path *) create_sort_path(root,
+ partially_grouped_rel,
+ path,
+ root->group_pathkeys,
+ -1.0);
if (parse->hasAggs)
add_partial_path(partially_grouped_rel, (Path *)
@@ -6965,9 +6800,9 @@ create_partial_grouping_paths(PlannerInfo *root,
partially_grouped_rel,
path,
partially_grouped_rel->reltarget,
- info->clauses ? AGG_SORTED : AGG_PLAIN,
+ parse->groupClause ? AGG_SORTED : AGG_PLAIN,
AGGSPLIT_INITIAL_SERIAL,
- info->clauses,
+ parse->groupClause,
NIL,
agg_partial_costs,
dNumPartialPartialGroups));
@@ -6976,10 +6811,59 @@ create_partial_grouping_paths(PlannerInfo *root,
create_group_path(root,
partially_grouped_rel,
path,
- info->clauses,
+ parse->groupClause,
NIL,
dNumPartialPartialGroups));
}
+
+ /*
+ * Now we may consider incremental sort on this path, but only
+ * when the path is not already sorted and when incremental sort
+ * is enabled.
+ */
+ if (is_sorted || !enable_incremental_sort)
+ continue;
+
+ /* Restore the input path (we might have added Sort on top). */
+ path = path_original;
+
+ /* no shared prefix, not point in building incremental sort */
+ if (presorted_keys == 0)
+ continue;
+
+ /*
+ * We should have already excluded pathkeys of length 1 because
+ * then presorted_keys > 0 would imply is_sorted was true.
+ */
+ Assert(list_length(root->group_pathkeys) != 1);
+
+ path = (Path *) create_incremental_sort_path(root,
+ partially_grouped_rel,
+ path,
+ root->group_pathkeys,
+ presorted_keys,
+ -1.0);
+
+ if (parse->hasAggs)
+ add_partial_path(partially_grouped_rel, (Path *)
+ create_agg_path(root,
+ partially_grouped_rel,
+ path,
+ partially_grouped_rel->reltarget,
+ parse->groupClause ? AGG_SORTED : AGG_PLAIN,
+ AGGSPLIT_INITIAL_SERIAL,
+ parse->groupClause,
+ NIL,
+ agg_partial_costs,
+ dNumPartialPartialGroups));
+ else
+ add_partial_path(partially_grouped_rel, (Path *)
+ create_group_path(root,
+ partially_grouped_rel,
+ path,
+ parse->groupClause,
+ NIL,
+ dNumPartialPartialGroups));
}
}