From 54a8a61abb3c629196e6e9a778f8527103df26c2 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Tue, 20 Mar 2018 14:12:58 -0400 Subject: [PATCH 1/3] Remove loop from 0 to 1. --- src/backend/optimizer/plan/planner.c | 289 +++++++++++++++++++++-------------- 1 file changed, 171 insertions(+), 118 deletions(-) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 4c11d84fd6..c05182d479 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -6378,14 +6378,32 @@ create_partial_grouping_paths(PlannerInfo *root, RelOptInfo *partially_grouped_rel; AggClauseCosts *agg_partial_costs = &extra->agg_partial_costs; AggClauseCosts *agg_final_costs = &extra->agg_final_costs; - Path *cheapest_path; - Size hashaggtablesize; + Path *cheapest_partial_path = NULL; + Path *cheapest_total_path = NULL; double dNumPartialGroups = 0; + double dNumPartialPartialGroups = 0; ListCell *lc; bool can_hash = (extra->flags & GROUPING_CAN_USE_HASH) != 0; bool can_sort = (extra->flags & GROUPING_CAN_USE_SORT) != 0; - bool use_partial_pathlist; - int i; + + /* + * Consider whether we should generate partially aggregated non-partial + * paths. We can only do this if we have a non-partial path, and in + * addition the caller must have requested it by setting + * extra->is_partial_aggregation or + * extra->perform_partial_partitionwise_aggregation. + */ + if (input_rel->pathlist != NIL && (extra->is_partial_aggregation || + extra->perform_partial_partitionwise_aggregation)) + cheapest_total_path = input_rel->cheapest_total_path; + + /* + * If parallelism is possible for grouped_rel, then we should consider + * generating partially-grouped partial paths. However, if the input rel + * has no partial paths, then we can't. + */ + if (grouped_rel->consider_parallel && input_rel->partial_pathlist != NIL) + cheapest_partial_path = linitial(input_rel->partial_pathlist); /* * Build a new upper relation to represent the result of partially @@ -6443,137 +6461,172 @@ create_partial_grouping_paths(PlannerInfo *root, extra->partial_costs_set = true; } - /* - * We loop twice, one to generate paths for partial_pathlist when parallel - * paths are possible and second time for generating paths in pathlist when - * we need partially aggregated results for the partitionwise grouping - * and/or aggregation. - */ - use_partial_pathlist = true; - for (i = 0; i < 2; i++) + /* Estimate number of partial groups. */ + if (cheapest_total_path != NULL) + dNumPartialGroups = + get_number_of_groups(root, + cheapest_total_path->rows, + gd, + extra->targetList); + if (cheapest_partial_path != NULL) + dNumPartialPartialGroups = + get_number_of_groups(root, + cheapest_partial_path->rows, + gd, + extra->targetList); + + if (can_sort && cheapest_total_path != NULL) { - if (use_partial_pathlist && !(grouped_rel->consider_parallel && - input_rel->partial_pathlist != NIL && - (extra->flags & GROUPING_CAN_PARTIAL_AGG) != 0)) - { - /* No parallel paths possible. */ - use_partial_pathlist = false; - continue; - } + /* This should have been checked previously */ + Assert(parse->hasAggs || parse->groupClause); - if (!use_partial_pathlist && !extra->is_partial_aggregation) + /* + * Use any available suitably-sorted path as input, and also consider + * sorting the cheapest partial path. + */ + foreach(lc, input_rel->pathlist) { - /* No partial partitiowise aggregation possible. */ - continue; - } + Path *path = (Path *) lfirst(lc); + bool is_sorted; - /* Get either total or partial cheapest path */ - cheapest_path = use_partial_pathlist ? linitial(input_rel->partial_pathlist) : - input_rel->cheapest_total_path; + 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); - /* Estimate number of partial groups. */ - dNumPartialGroups = get_number_of_groups(root, - cheapest_path->rows, - gd, - extra->targetList); + 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)); + } + } + } - if (can_sort) + if (can_sort && cheapest_partial_path != NULL) + { + /* Similar to above logic, but for partial paths. */ + foreach(lc, input_rel->partial_pathlist) { - List *pathlist; - - /* This should have been checked previously */ - Assert(parse->hasAggs || parse->groupClause); - - /* Get appropriate pathlist */ - pathlist = use_partial_pathlist ? input_rel->partial_pathlist : - input_rel->pathlist; + Path *path = (Path *) lfirst(lc); + bool is_sorted; - /* - * Use any available suitably-sorted path as input, and also - * consider sorting the cheapest path. - */ - foreach(lc, pathlist) + is_sorted = pathkeys_contained_in(root->group_pathkeys, + path->pathkeys); + if (path == cheapest_partial_path || is_sorted) { - Path *path = (Path *) lfirst(lc); - bool is_sorted; - Path *gpath; + /* 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); - is_sorted = pathkeys_contained_in(root->group_pathkeys, - path->pathkeys); - if (path == cheapest_path || is_sorted) - { - /* Sort the cheapest 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) - gpath = (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 - gpath = (Path *) create_group_path(root, - partially_grouped_rel, - path, - parse->groupClause, - NIL, - dNumPartialGroups); - - if (use_partial_pathlist) - add_partial_path(partially_grouped_rel, gpath); - else - add_path(partially_grouped_rel, gpath); - } + 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)); } } + } - if (can_hash) - { - /* Checked above */ - Assert(parse->hasAggs || parse->groupClause); + if (can_hash && cheapest_total_path != NULL) + { + Size hashaggtablesize; - hashaggtablesize = - estimate_hashagg_tablesize(cheapest_path, - agg_partial_costs, - dNumPartialGroups); + /* Checked above */ + Assert(parse->hasAggs || parse->groupClause); - /* - * Tentatively produce a partial HashAgg Path, depending on if it - * looks as if the hash table will fit in work_mem. - */ - if (hashaggtablesize < work_mem * 1024L) - { - Path *gpath; - - gpath = (Path *) create_agg_path(root, - partially_grouped_rel, - cheapest_path, - partially_grouped_rel->reltarget, - AGG_HASHED, - AGGSPLIT_INITIAL_SERIAL, - parse->groupClause, - NIL, - agg_partial_costs, - dNumPartialGroups); - - if (use_partial_pathlist) - add_partial_path(partially_grouped_rel, gpath); - else - add_path(partially_grouped_rel, gpath); - } + hashaggtablesize = + estimate_hashagg_tablesize(cheapest_total_path, + agg_partial_costs, + dNumPartialGroups); + + /* + * Tentatively produce a partial HashAgg Path, depending on if it + * looks as if the hash table will fit in work_mem. + */ + if (hashaggtablesize < work_mem * 1024L && + cheapest_total_path != NULL) + { + add_path(partially_grouped_rel, (Path *) + create_agg_path(root, + partially_grouped_rel, + cheapest_total_path, + partially_grouped_rel->reltarget, + AGG_HASHED, + AGGSPLIT_INITIAL_SERIAL, + parse->groupClause, + NIL, + agg_partial_costs, + dNumPartialGroups)); } + } + + if (can_hash && cheapest_partial_path != NULL) + { + Size hashaggtablesize; + + hashaggtablesize = + estimate_hashagg_tablesize(cheapest_partial_path, + agg_partial_costs, + dNumPartialPartialGroups); - use_partial_pathlist = false; + /* Do the same for partial paths. */ + if (hashaggtablesize < work_mem * 1024L && + cheapest_partial_path != NULL) + { + add_partial_path(partially_grouped_rel, (Path *) + create_agg_path(root, + partially_grouped_rel, + cheapest_partial_path, + partially_grouped_rel->reltarget, + AGG_HASHED, + AGGSPLIT_INITIAL_SERIAL, + parse->groupClause, + NIL, + agg_partial_costs, + dNumPartialPartialGroups)); + } } /* -- 2.14.3 (Apple Git-98)