Generalize the common code of adding sort before processing of grouping

Extract the repetitive code pattern into a new function make_ordered_path().

Discussion: https://postgr.es/m/CAPpHfdtzaVa7S4onKy3YvttF2rrH5hQNHx9HtcSTLbpjx%2BMJ%2Bw%40mail.gmail.com
Author: Andrei Lepikhov
This commit is contained in:
Alexander Korotkov 2024-01-21 22:19:47 +02:00
parent 58447e3189
commit 7ab80ac1ca
1 changed files with 80 additions and 148 deletions

View File

@ -6809,6 +6809,58 @@ done:
return parallel_workers;
}
/*
* make_ordered_path
* Return a path ordered by 'pathkeys' based on the given 'path'. May
* return NULL if it doesn't make sense to generate an ordered path in
* this case.
*/
static Path *
make_ordered_path(PlannerInfo *root, RelOptInfo *rel, Path *path,
Path *cheapest_path, List *pathkeys)
{
bool is_sorted;
int presorted_keys;
is_sorted = pathkeys_count_contained_in(pathkeys,
path->pathkeys,
&presorted_keys);
if (!is_sorted)
{
/*
* 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_path &&
(presorted_keys == 0 || !enable_incremental_sort))
return NULL;
/*
* 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,
pathkeys,
-1.0);
else
path = (Path *) create_incremental_sort_path(root,
rel,
path,
pathkeys,
presorted_keys,
-1.0);
}
return path;
}
/*
* add_paths_to_grouping_rel
*
@ -6840,45 +6892,15 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
foreach(lc, input_rel->pathlist)
{
Path *path = (Path *) lfirst(lc);
bool is_sorted;
int presorted_keys;
is_sorted = pathkeys_count_contained_in(root->group_pathkeys,
path->pathkeys,
&presorted_keys);
path = make_ordered_path(root,
grouped_rel,
path,
cheapest_path,
root->group_pathkeys);
if (!is_sorted)
{
/*
* 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_path &&
(presorted_keys == 0 || !enable_incremental_sort))
continue;
/*
* 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,
grouped_rel,
path,
root->group_pathkeys,
-1.0);
else
path = (Path *) create_incremental_sort_path(root,
grouped_rel,
path,
root->group_pathkeys,
presorted_keys,
-1.0);
}
if (path == NULL)
continue;
/* Now decide what to stick atop it */
if (parse->groupingSets)
@ -6935,46 +6957,15 @@ add_paths_to_grouping_rel(PlannerInfo *root, RelOptInfo *input_rel,
foreach(lc, partially_grouped_rel->pathlist)
{
Path *path = (Path *) lfirst(lc);
bool is_sorted;
int presorted_keys;
is_sorted = pathkeys_count_contained_in(root->group_pathkeys,
path->pathkeys,
&presorted_keys);
path = make_ordered_path(root,
grouped_rel,
path,
partially_grouped_rel->cheapest_total_path,
root->group_pathkeys);
if (!is_sorted)
{
/*
* 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 != partially_grouped_rel->cheapest_total_path &&
(presorted_keys == 0 || !enable_incremental_sort))
continue;
/*
* We've no need to consider both a sort and incremental
* sort. We'll just do a sort if there are no pre-sorted
* keys and an incremental sort when there are presorted
* keys.
*/
if (presorted_keys == 0 || !enable_incremental_sort)
path = (Path *) create_sort_path(root,
grouped_rel,
path,
root->group_pathkeys,
-1.0);
else
path = (Path *) create_incremental_sort_path(root,
grouped_rel,
path,
root->group_pathkeys,
presorted_keys,
-1.0);
}
if (path == NULL)
continue;
if (parse->hasAggs)
add_path(grouped_rel, (Path *)
@ -7200,44 +7191,15 @@ create_partial_grouping_paths(PlannerInfo *root,
foreach(lc, input_rel->pathlist)
{
Path *path = (Path *) lfirst(lc);
bool is_sorted;
int presorted_keys;
is_sorted = pathkeys_count_contained_in(root->group_pathkeys,
path->pathkeys,
&presorted_keys);
if (!is_sorted)
{
/*
* 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_total_path &&
(presorted_keys == 0 || !enable_incremental_sort))
continue;
path = make_ordered_path(root,
partially_grouped_rel,
path,
cheapest_total_path,
root->group_pathkeys);
/*
* 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,
partially_grouped_rel,
path,
root->group_pathkeys,
-1.0);
else
path = (Path *) create_incremental_sort_path(root,
partially_grouped_rel,
path,
root->group_pathkeys,
presorted_keys,
-1.0);
}
if (path == NULL)
continue;
if (parse->hasAggs)
add_path(partially_grouped_rel, (Path *)
@ -7268,45 +7230,15 @@ create_partial_grouping_paths(PlannerInfo *root,
foreach(lc, input_rel->partial_pathlist)
{
Path *path = (Path *) lfirst(lc);
bool is_sorted;
int presorted_keys;
is_sorted = pathkeys_count_contained_in(root->group_pathkeys,
path->pathkeys,
&presorted_keys);
path = make_ordered_path(root,
partially_grouped_rel,
path,
cheapest_partial_path,
root->group_pathkeys);
if (!is_sorted)
{
/*
* 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;
/*
* 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,
partially_grouped_rel,
path,
root->group_pathkeys,
-1.0);
else
path = (Path *) create_incremental_sort_path(root,
partially_grouped_rel,
path,
root->group_pathkeys,
presorted_keys,
-1.0);
}
if (path == NULL)
continue;
if (parse->hasAggs)
add_partial_path(partially_grouped_rel, (Path *)