Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commitf199303

Browse files
committed
Avoid making a separate pass over the query to check for partializability.
It's rather silly to make a separate pass over the tlist + HAVING qual,and a separate set of visits to the syscache, when get_agg_clause_costsalready has all the required information in hand. This nets out as lesscode as well as fewer cycles.
1 parent19e972d commitf199303

File tree

4 files changed

+54
-118
lines changed

4 files changed

+54
-118
lines changed

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

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,10 @@ static double get_number_of_groups(PlannerInfo *root,
110110
List*rollup_groupclauses);
111111
staticvoidset_grouped_rel_consider_parallel(PlannerInfo*root,
112112
RelOptInfo*grouped_rel,
113-
PathTarget*target);
114-
staticSizeestimate_hashagg_tablesize(Path*path,AggClauseCosts*agg_costs,
113+
PathTarget*target,
114+
constAggClauseCosts*agg_costs);
115+
staticSizeestimate_hashagg_tablesize(Path*path,
116+
constAggClauseCosts*agg_costs,
115117
doubledNumGroups);
116118
staticRelOptInfo*create_grouping_paths(PlannerInfo*root,
117119
RelOptInfo*input_rel,
@@ -3207,7 +3209,8 @@ get_number_of_groups(PlannerInfo *root,
32073209
*/
32083210
staticvoid
32093211
set_grouped_rel_consider_parallel(PlannerInfo*root,RelOptInfo*grouped_rel,
3210-
PathTarget*target)
3212+
PathTarget*target,
3213+
constAggClauseCosts*agg_costs)
32113214
{
32123215
Query*parse=root->parse;
32133216

@@ -3240,15 +3243,14 @@ set_grouped_rel_consider_parallel(PlannerInfo *root, RelOptInfo *grouped_rel,
32403243
return;
32413244

32423245
/*
3243-
* All that's left to check now is to make sure all aggregate functions
3244-
* support partial mode. If there's no aggregates then we can skip
3245-
* checking that.
3246+
* If we have any non-partial-capable aggregates, or if any of them can't
3247+
* be serialized, we can't go parallel.
32463248
*/
3247-
if (!parse->hasAggs)
3248-
grouped_rel->consider_parallel= true;
3249-
elseif (aggregates_allow_partial((Node*)target->exprs)==PAT_ANY&&
3250-
aggregates_allow_partial(root->parse->havingQual)==PAT_ANY)
3251-
grouped_rel->consider_parallel= true;
3249+
if (agg_costs->hasNonPartial||agg_costs->hasNonSerial)
3250+
return;
3251+
3252+
/* OK, consider parallelization */
3253+
grouped_rel->consider_parallel= true;
32523254
}
32533255

32543256
/*
@@ -3257,7 +3259,7 @@ set_grouped_rel_consider_parallel(PlannerInfo *root, RelOptInfo *grouped_rel,
32573259
* require based on the agg_costs, path width and dNumGroups.
32583260
*/
32593261
staticSize
3260-
estimate_hashagg_tablesize(Path*path,AggClauseCosts*agg_costs,
3262+
estimate_hashagg_tablesize(Path*path,constAggClauseCosts*agg_costs,
32613263
doubledNumGroups)
32623264
{
32633265
Sizehashentrysize;
@@ -3411,7 +3413,8 @@ create_grouping_paths(PlannerInfo *root,
34113413
* going to be safe to do so.
34123414
*/
34133415
if (input_rel->partial_pathlist!=NIL)
3414-
set_grouped_rel_consider_parallel(root,grouped_rel,target);
3416+
set_grouped_rel_consider_parallel(root,grouped_rel,
3417+
target,&agg_costs);
34153418

34163419
/*
34173420
* Determine whether it's possible to perform sort-based implementations

‎src/backend/optimizer/util/clauses.c

Lines changed: 34 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,6 @@
5252
#include"utils/syscache.h"
5353
#include"utils/typcache.h"
5454

55-
typedefstruct
56-
{
57-
PartialAggTypeallowedtype;
58-
}partial_agg_context;
5955

6056
typedefstruct
6157
{
@@ -98,8 +94,6 @@ typedef struct
9894
boolallow_restricted;
9995
}has_parallel_hazard_arg;
10096

101-
staticboolaggregates_allow_partial_walker(Node*node,
102-
partial_agg_context*context);
10397
staticboolcontain_agg_clause_walker(Node*node,void*context);
10498
staticboolget_agg_clause_costs_walker(Node*node,
10599
get_agg_clause_costs_context*context);
@@ -403,81 +397,6 @@ make_ands_implicit(Expr *clause)
403397
*Aggregate-function clause manipulation
404398
*****************************************************************************/
405399

406-
/*
407-
* aggregates_allow_partial
408-
*Recursively search for Aggref clauses and determine the maximum
409-
*level of partial aggregation which can be supported.
410-
*/
411-
PartialAggType
412-
aggregates_allow_partial(Node*clause)
413-
{
414-
partial_agg_contextcontext;
415-
416-
/* initially any type is okay, until we find Aggrefs which say otherwise */
417-
context.allowedtype=PAT_ANY;
418-
419-
if (!aggregates_allow_partial_walker(clause,&context))
420-
returncontext.allowedtype;
421-
returncontext.allowedtype;
422-
}
423-
424-
staticbool
425-
aggregates_allow_partial_walker(Node*node,partial_agg_context*context)
426-
{
427-
if (node==NULL)
428-
return false;
429-
if (IsA(node,Aggref))
430-
{
431-
Aggref*aggref= (Aggref*)node;
432-
HeapTupleaggTuple;
433-
Form_pg_aggregateaggform;
434-
435-
Assert(aggref->agglevelsup==0);
436-
437-
/*
438-
* We can't perform partial aggregation with Aggrefs containing a
439-
* DISTINCT or ORDER BY clause.
440-
*/
441-
if (aggref->aggdistinct||aggref->aggorder)
442-
{
443-
context->allowedtype=PAT_DISABLED;
444-
return true;/* abort search */
445-
}
446-
aggTuple=SearchSysCache1(AGGFNOID,
447-
ObjectIdGetDatum(aggref->aggfnoid));
448-
if (!HeapTupleIsValid(aggTuple))
449-
elog(ERROR,"cache lookup failed for aggregate %u",
450-
aggref->aggfnoid);
451-
aggform= (Form_pg_aggregate)GETSTRUCT(aggTuple);
452-
453-
/*
454-
* If there is no combine function, then partial aggregation is not
455-
* possible.
456-
*/
457-
if (!OidIsValid(aggform->aggcombinefn))
458-
{
459-
ReleaseSysCache(aggTuple);
460-
context->allowedtype=PAT_DISABLED;
461-
return true;/* abort search */
462-
}
463-
464-
/*
465-
* If we find any aggs with an internal transtype then we must check
466-
* whether these have serialization/deserialization functions;
467-
* otherwise, we set the maximum allowed type to PAT_INTERNAL_ONLY.
468-
*/
469-
if (aggform->aggtranstype==INTERNALOID&&
470-
(!OidIsValid(aggform->aggserialfn)||
471-
!OidIsValid(aggform->aggdeserialfn)))
472-
context->allowedtype=PAT_INTERNAL_ONLY;
473-
474-
ReleaseSysCache(aggTuple);
475-
return false;/* continue searching */
476-
}
477-
returnexpression_tree_walker(node,aggregates_allow_partial_walker,
478-
(void*)context);
479-
}
480-
481400
/*
482401
* contain_agg_clause
483402
* Recursively search for Aggref/GroupingFunc nodes within a clause.
@@ -529,8 +448,9 @@ contain_agg_clause_walker(Node *node, void *context)
529448
*
530449
* We count the nodes, estimate their execution costs, and estimate the total
531450
* space needed for their transition state values if all are evaluated in
532-
* parallel (as would be done in a HashAgg plan). See AggClauseCosts for
533-
* the exact set of statistics collected.
451+
* parallel (as would be done in a HashAgg plan). Also, we check whether
452+
* partial aggregation is feasible. See AggClauseCosts for the exact set
453+
* of statistics collected.
534454
*
535455
* In addition, we mark Aggref nodes with the correct aggtranstype, so
536456
* that that doesn't need to be done repeatedly. (That makes this function's
@@ -616,10 +536,40 @@ get_agg_clause_costs_walker(Node *node, get_agg_clause_costs_context *context)
616536
aggref->aggtranstype=aggtranstype;
617537
}
618538

619-
/* count it; note ordered-set aggs always have nonempty aggorder */
539+
/*
540+
* Count it, and check for cases requiring ordered input. Note that
541+
* ordered-set aggs always have nonempty aggorder. Any ordered-input
542+
* case also defeats partial aggregation.
543+
*/
620544
costs->numAggs++;
621545
if (aggref->aggorder!=NIL||aggref->aggdistinct!=NIL)
546+
{
622547
costs->numOrderedAggs++;
548+
costs->hasNonPartial= true;
549+
}
550+
551+
/*
552+
* Check whether partial aggregation is feasible, unless we already
553+
* found out that we can't do it.
554+
*/
555+
if (!costs->hasNonPartial)
556+
{
557+
/*
558+
* If there is no combine function, then partial aggregation is
559+
* not possible.
560+
*/
561+
if (!OidIsValid(aggcombinefn))
562+
costs->hasNonPartial= true;
563+
564+
/*
565+
* If we have any aggs with transtype INTERNAL then we must check
566+
* whether they have serialization/deserialization functions; if
567+
* not, we can't serialize partial-aggregation results.
568+
*/
569+
elseif (aggtranstype==INTERNALOID&&
570+
(!OidIsValid(aggserialfn)|| !OidIsValid(aggdeserialfn)))
571+
costs->hasNonSerial= true;
572+
}
623573

624574
/*
625575
* Add the appropriate component function execution costs to

‎src/include/nodes/relation.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,15 @@ typedef struct QualCost
5050
* Costing aggregate function execution requires these statistics about
5151
* the aggregates to be executed by a given Agg node. Note that the costs
5252
* include the execution costs of the aggregates' argument expressions as
53-
* well as the aggregate functions themselves.
53+
* well as the aggregate functions themselves. Also, the fields must be
54+
* defined so that initializing the struct to zeroes with memset is correct.
5455
*/
5556
typedefstructAggClauseCosts
5657
{
5758
intnumAggs;/* total number of aggregate functions */
5859
intnumOrderedAggs;/* number w/ DISTINCT/ORDER BY/WITHIN GROUP */
60+
boolhasNonPartial;/* does any agg not support partial mode? */
61+
boolhasNonSerial;/* is any partial agg non-serializable? */
5962
QualCosttransCost;/* total per-input-row execution costs */
6063
CostfinalCost;/* total per-aggregated-row costs */
6164
SizetransitionSpace;/* space for pass-by-ref transition data */

‎src/include/optimizer/clauses.h

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,25 +27,6 @@ typedef struct
2727
List**windowFuncs;/* lists of WindowFuncs for each winref */
2828
}WindowFuncLists;
2929

30-
/*
31-
* PartialAggType
32-
*PartialAggType stores whether partial aggregation is allowed and
33-
*which context it is allowed in. We require three states here as there are
34-
*two different contexts in which partial aggregation is safe. For aggregates
35-
*which have an 'stype' of INTERNAL, it is okay to pass a pointer to the
36-
*aggregate state within a single process, since the datum is just a
37-
*pointer. In cases where the aggregate state must be passed between
38-
*different processes, for example during parallel aggregation, passing
39-
*pointers directly is not going to work.
40-
*/
41-
typedefenum
42-
{
43-
PAT_ANY=0,/* Any type of partial aggregation is okay. */
44-
PAT_INTERNAL_ONLY,/* Some aggregates support only internal mode. */
45-
PAT_DISABLED/* Some aggregates don't support partial mode
46-
* at all */
47-
}PartialAggType;
48-
4930
externExpr*make_opclause(Oidopno,Oidopresulttype,boolopretset,
5031
Expr*leftop,Expr*rightop,
5132
Oidopcollid,Oidinputcollid);
@@ -65,7 +46,6 @@ extern Node *make_and_qual(Node *qual1, Node *qual2);
6546
externExpr*make_ands_explicit(List*andclauses);
6647
externList*make_ands_implicit(Expr*clause);
6748

68-
externPartialAggTypeaggregates_allow_partial(Node*clause);
6949
externboolcontain_agg_clause(Node*clause);
7050
externvoidget_agg_clause_costs(PlannerInfo*root,Node*clause,
7151
AggSplitaggsplit,AggClauseCosts*costs);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp