From 7ab80ac1caf9f48064190802e1068ef89e2883c4 Mon Sep 17 00:00:00 2001 From: Alexander Korotkov Date: Sun, 21 Jan 2024 22:19:47 +0200 Subject: [PATCH] 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 --- src/backend/optimizer/plan/planner.c | 228 ++++++++++----------------- 1 file changed, 80 insertions(+), 148 deletions(-) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 667723b675..014b179c3f 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -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 *)