Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b5996c2

Browse filesBrowse files
committed
Determine grouping strategies in create_grouping_paths.
Partition-wise aggregate will call create_ordinary_grouping_paths multiple times and we don't want to redo this work every time; have the caller do it instead and pass the details down. Patch by me, reviewed by Ashutosh Bapat. Discussion: http://postgr.es/m/CA+TgmoY7VYYn9a7YHj1nJL6zj6BkHmt4K-un9LRmXkyqRZyynA@mail.gmail.com
1 parent 4f15e5d commit b5996c2
Copy full SHA for b5996c2

File tree

Expand file treeCollapse file tree

1 file changed

+82
-60
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+82
-60
lines changed

‎src/backend/optimizer/plan/planner.c

Copy file name to clipboardExpand all lines: src/backend/optimizer/plan/planner.c
+82-60Lines changed: 82 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,25 @@ typedef struct
9393
List *groupClause; /* overrides parse->groupClause */
9494
} standard_qp_extra;
9595

96+
/*
97+
* Various flags indicating what kinds of grouping are possible.
98+
*
99+
* GROUPING_CAN_USE_SORT should be set if it's possible to perform
100+
* sort-based implementations of grouping. When grouping sets are in use,
101+
* this will be true if sorting is potentially usable for any of the grouping
102+
* sets, even if it's not usable for all of them.
103+
*
104+
* GROUPING_CAN_USE_HASH should be set if it's possible to perform
105+
* hash-based implementations of grouping.
106+
*
107+
* GROUPING_CAN_PARTIAL_AGG should be set if the aggregation is of a type
108+
* for which we support partial aggregation (not, for example, grouping sets).
109+
* It says nothing about parallel-safety or the availability of suitable paths.
110+
*/
111+
#define GROUPING_CAN_USE_SORT 0x0001
112+
#define GROUPING_CAN_USE_HASH 0x0002
113+
#define GROUPING_CAN_PARTIAL_AGG 0x0004
114+
96115
/*
97116
* Data specific to grouping sets
98117
*/
@@ -149,7 +168,7 @@ static void create_ordinary_grouping_paths(PlannerInfo *root,
149168
RelOptInfo *input_rel,
150169
PathTarget *target, RelOptInfo *grouped_rel,
151170
const AggClauseCosts *agg_costs,
152-
grouping_sets_data *gd);
171+
grouping_sets_data *gd, int flags);
153172
static void consider_groupingsets_paths(PlannerInfo *root,
154173
RelOptInfo *grouped_rel,
155174
Path *path,
@@ -215,8 +234,8 @@ static RelOptInfo *create_partial_grouping_paths(PlannerInfo *root,
215234
bool can_hash,
216235
AggClauseCosts *agg_final_costs);
217236
static void gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel);
218-
static bool can_parallel_agg(PlannerInfo *root, RelOptInfo *input_rel,
219-
RelOptInfo *grouped_rel, const AggClauseCosts *agg_costs);
237+
static bool can_partial_agg(PlannerInfo *root,
238+
const AggClauseCosts *agg_costs);
220239

221240

222241
/*****************************************************************************
@@ -3720,8 +3739,58 @@ create_grouping_paths(PlannerInfo *root,
37203739
if (is_degenerate_grouping(root))
37213740
create_degenerate_grouping_paths(root, input_rel, target, grouped_rel);
37223741
else
3742+
{
3743+
int flags = 0;
3744+
3745+
/*
3746+
* Determine whether it's possible to perform sort-based
3747+
* implementations of grouping. (Note that if groupClause is empty,
3748+
* grouping_is_sortable() is trivially true, and all the
3749+
* pathkeys_contained_in() tests will succeed too, so that we'll
3750+
* consider every surviving input path.)
3751+
*
3752+
* If we have grouping sets, we might be able to sort some but not all
3753+
* of them; in this case, we need can_sort to be true as long as we
3754+
* must consider any sorted-input plan.
3755+
*/
3756+
if ((gd && gd->rollups != NIL)
3757+
|| grouping_is_sortable(parse->groupClause))
3758+
flags |= GROUPING_CAN_USE_SORT;
3759+
3760+
/*
3761+
* Determine whether we should consider hash-based implementations of
3762+
* grouping.
3763+
*
3764+
* Hashed aggregation only applies if we're grouping. If we have
3765+
* grouping sets, some groups might be hashable but others not; in
3766+
* this case we set can_hash true as long as there is nothing globally
3767+
* preventing us from hashing (and we should therefore consider plans
3768+
* with hashes).
3769+
*
3770+
* Executor doesn't support hashed aggregation with DISTINCT or ORDER
3771+
* BY aggregates. (Doing so would imply storing *all* the input
3772+
* values in the hash table, and/or running many sorts in parallel,
3773+
* either of which seems like a certain loser.) We similarly don't
3774+
* support ordered-set aggregates in hashed aggregation, but that case
3775+
* is also included in the numOrderedAggs count.
3776+
*
3777+
* Note: grouping_is_hashable() is much more expensive to check than
3778+
* the other gating conditions, so we want to do it last.
3779+
*/
3780+
if ((parse->groupClause != NIL &&
3781+
agg_costs->numOrderedAggs == 0 &&
3782+
(gd ? gd->any_hashable : grouping_is_hashable(parse->groupClause))))
3783+
flags |= GROUPING_CAN_USE_HASH;
3784+
3785+
/*
3786+
* Determine whether partial aggregation is possible.
3787+
*/
3788+
if (can_partial_agg(root, agg_costs))
3789+
flags |= GROUPING_CAN_PARTIAL_AGG;
3790+
37233791
create_ordinary_grouping_paths(root, input_rel, target, grouped_rel,
3724-
agg_costs, gd);
3792+
agg_costs, gd, flags);
3793+
}
37253794

37263795
set_cheapest(grouped_rel);
37273796
return grouped_rel;
@@ -3820,15 +3889,15 @@ static void
38203889
create_ordinary_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
38213890
PathTarget *target, RelOptInfo *grouped_rel,
38223891
const AggClauseCosts *agg_costs,
3823-
grouping_sets_data *gd)
3892+
grouping_sets_data *gd, int flags)
38243893
{
38253894
Query *parse = root->parse;
38263895
Path *cheapest_path = input_rel->cheapest_total_path;
38273896
RelOptInfo *partially_grouped_rel = NULL;
38283897
AggClauseCosts agg_final_costs; /* parallel only */
38293898
double dNumGroups;
3830-
bool can_hash;
3831-
bool can_sort;
3899+
bool can_hash = (flags & GROUPING_CAN_USE_HASH) != 0;
3900+
bool can_sort = (flags & GROUPING_CAN_USE_SORT) != 0;
38323901

38333902
/*
38343903
* Estimate number of groups.
@@ -3838,50 +3907,14 @@ create_ordinary_grouping_paths(PlannerInfo *root, RelOptInfo *input_rel,
38383907
gd,
38393908
parse->targetList);
38403909

3841-
/*
3842-
* Determine whether it's possible to perform sort-based implementations
3843-
* of grouping. (Note that if groupClause is empty,
3844-
* grouping_is_sortable() is trivially true, and all the
3845-
* pathkeys_contained_in() tests will succeed too, so that we'll consider
3846-
* every surviving input path.)
3847-
*
3848-
* If we have grouping sets, we might be able to sort some but not all of
3849-
* them; in this case, we need can_sort to be true as long as we must
3850-
* consider any sorted-input plan.
3851-
*/
3852-
can_sort = (gd && gd->rollups != NIL)
3853-
|| grouping_is_sortable(parse->groupClause);
3854-
3855-
/*
3856-
* Determine whether we should consider hash-based implementations of
3857-
* grouping.
3858-
*
3859-
* Hashed aggregation only applies if we're grouping. If we have grouping
3860-
* sets, some groups might be hashable but others not; in this case we set
3861-
* can_hash true as long as there is nothing globally preventing us from
3862-
* hashing (and we should therefore consider plans with hashes).
3863-
*
3864-
* Executor doesn't support hashed aggregation with DISTINCT or ORDER BY
3865-
* aggregates. (Doing so would imply storing *all* the input values in
3866-
* the hash table, and/or running many sorts in parallel, either of which
3867-
* seems like a certain loser.) We similarly don't support ordered-set
3868-
* aggregates in hashed aggregation, but that case is also included in the
3869-
* numOrderedAggs count.
3870-
*
3871-
* Note: grouping_is_hashable() is much more expensive to check than the
3872-
* other gating conditions, so we want to do it last.
3873-
*/
3874-
can_hash = (parse->groupClause != NIL &&
3875-
agg_costs->numOrderedAggs == 0 &&
3876-
(gd ? gd->any_hashable : grouping_is_hashable(parse->groupClause)));
3877-
38783910
/*
38793911
* Before generating paths for grouped_rel, we first generate any possible
38803912
* partially grouped paths; that way, later code can easily consider both
38813913
* parallel and non-parallel approaches to grouping.
38823914
*/
38833915
MemSet(&agg_final_costs, 0, sizeof(AggClauseCosts));
3884-
if (can_parallel_agg(root, input_rel, grouped_rel, agg_costs))
3916+
if (grouped_rel->consider_parallel && input_rel->partial_pathlist != NIL
3917+
&& (flags & GROUPING_CAN_PARTIAL_AGG) != 0)
38853918
{
38863919
partially_grouped_rel =
38873920
create_partial_grouping_paths(root,
@@ -6490,28 +6523,17 @@ gather_grouping_paths(PlannerInfo *root, RelOptInfo *rel)
64906523
}
64916524

64926525
/*
6493-
* can_parallel_agg
6526+
* can_partial_agg
64946527
*
6495-
* Determines whether or not parallel grouping and/or aggregation is possible.
6528+
* Determines whether or not partial grouping and/or aggregation is possible.
64966529
* Returns true when possible, false otherwise.
64976530
*/
64986531
static bool
6499-
can_parallel_agg(PlannerInfo *root, RelOptInfo *input_rel,
6500-
RelOptInfo *grouped_rel, const AggClauseCosts *agg_costs)
6532+
can_partial_agg(PlannerInfo *root, const AggClauseCosts *agg_costs)
65016533
{
65026534
Query *parse = root->parse;
65036535

6504-
if (!grouped_rel->consider_parallel)
6505-
{
6506-
/* Not even parallel-safe. */
6507-
return false;
6508-
}
6509-
else if (input_rel->partial_pathlist == NIL)
6510-
{
6511-
/* Nothing to use as input for partial aggregate. */
6512-
return false;
6513-
}
6514-
else if (!parse->hasAggs && parse->groupClause == NIL)
6536+
if (!parse->hasAggs && parse->groupClause == NIL)
65156537
{
65166538
/*
65176539
* We don't know how to do parallel aggregation unless we have either

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.