summaryrefslogtreecommitdiff
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.c710
1 files changed, 270 insertions, 440 deletions
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 8014d1fd250..9c5836683c6 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -2758,9 +2758,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.
@@ -6433,148 +6432,30 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
if (can_sort)
{
- List *group_pathkeys;
- List *orderAggPathkeys;
- int numAggPathkeys;
-
- numAggPathkeys = list_length(root->group_pathkeys) -
- root->num_groupby_pathkeys;
-
- if (numAggPathkeys > 0)
- {
- group_pathkeys = list_copy_head(root->group_pathkeys,
- root->num_groupby_pathkeys);
- orderAggPathkeys = list_copy_tail(root->group_pathkeys,
- root->num_groupby_pathkeys);
- }
- else
- {
- group_pathkeys = root->group_pathkeys;
- orderAggPathkeys = NIL;
- }
-
/*
* Use any available suitably-sorted path as input, and also consider
* sorting the cheapest-total path.
*/
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_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,
- orderAggPathkeys);
-
- Assert(pathkey_orderings != NIL);
+ is_sorted = pathkeys_count_contained_in(root->group_pathkeys,
+ path->pathkeys,
+ &presorted_keys);
- /* 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)
@@ -6594,9 +6475,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));
@@ -6611,7 +6492,7 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
create_group_path(root,
grouped_rel,
path,
- info->clauses,
+ parse->groupClause,
havingQual,
dNumGroups));
}
@@ -6621,6 +6502,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);
+ }
}
/*
@@ -6631,128 +6585,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;
- List *pathkey_orderings = NIL;
- 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,
- orderAggPathkeys);
+ bool is_sorted;
+ int presorted_keys;
- Assert(pathkey_orderings != NIL);
+ 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));
}
}
}
@@ -6946,26 +6872,6 @@ create_partial_grouping_paths(PlannerInfo *root,
if (can_sort && cheapest_total_path != NULL)
{
- List *group_pathkeys;
- List *orderAggPathkeys;
- int numAggPathkeys;
-
- numAggPathkeys = list_length(root->group_pathkeys) -
- root->num_groupby_pathkeys;
-
- if (numAggPathkeys > 0)
- {
- group_pathkeys = list_copy_head(root->group_pathkeys,
- root->num_groupby_pathkeys);
- orderAggPathkeys = list_copy_tail(root->group_pathkeys,
- root->num_groupby_pathkeys);
- }
- else
- {
- group_pathkeys = root->group_pathkeys;
- orderAggPathkeys = NIL;
- }
-
/* This should have been checked previously */
Assert(parse->hasAggs || parse->groupClause);
@@ -6975,69 +6881,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_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,
- orderAggPathkeys);
-
- Assert(pathkey_orderings != NIL);
-
- /* process all potentially interesting grouping reorderings */
- foreach(lc2, pathkey_orderings)
- {
- 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);
+ bool is_sorted;
- 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);
- }
+ is_sorted = pathkeys_contained_in(root->group_pathkeys,
+ path->pathkeys);
+ 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,
+ 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));
}
}
@@ -7047,8 +6925,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)
{
@@ -7103,122 +6979,27 @@ create_partial_grouping_paths(PlannerInfo *root,
if (can_sort && cheapest_partial_path != NULL)
{
- List *group_pathkeys;
- List *orderAggPathkeys;
- int numAggPathkeys;
-
- numAggPathkeys = list_length(root->group_pathkeys) -
- root->num_groupby_pathkeys;
-
- if (numAggPathkeys > 0)
- {
- group_pathkeys = list_copy_head(root->group_pathkeys,
- root->num_groupby_pathkeys);
- orderAggPathkeys = list_copy_tail(root->group_pathkeys,
- root->num_groupby_pathkeys);
- }
- else
- {
- group_pathkeys = root->group_pathkeys;
- orderAggPathkeys = NIL;
- }
-
/* 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;
- List *pathkey_orderings = NIL;
- 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,
- orderAggPathkeys);
+ bool is_sorted;
+ int presorted_keys;
- Assert(pathkey_orderings != NIL);
+ is_sorted = pathkeys_count_contained_in(root->group_pathkeys,
+ path->pathkeys,
+ &presorted_keys);
- /* 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 *)
@@ -7226,9 +7007,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));
@@ -7237,10 +7018,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));
}
}