diff options
Diffstat (limited to 'src/backend/optimizer/plan/planner.c')
-rw-r--r-- | src/backend/optimizer/plan/planner.c | 654 |
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)); } } |