Skip to content

Commit f9ccf92

Browse files
committed
Simplify representation of aggregate transition values a bit.
Previously aggregate transition values for hash and other forms of aggregation (i.e. sort and no group by) were represented differently. Hash based aggregation used a grouping set indexed array pointing to an array of transition values, whereas other forms of aggregation used one flattened array with the index being computed out of grouping set and transition offsets. That made upcoming changes hard, so represent both as grouping set indexed array of per-group data. As a nice side-effect this also makes aggregation slightly faster, because computing offsets with `transno + (setno * numTrans)` turns out not to be that cheap (too big for x86 lea for example). Author: Andres Freund Discussion: https://postgr.es/m/[email protected]
1 parent 5dc692f commit f9ccf92

File tree

2 files changed

+65
-51
lines changed

2 files changed

+65
-51
lines changed

src/backend/executor/nodeAgg.c

+61-49
Original file line numberDiff line numberDiff line change
@@ -532,13 +532,14 @@ static void select_current_set(AggState *aggstate, int setno, bool is_hash);
532532
static void initialize_phase(AggState *aggstate, int newphase);
533533
static TupleTableSlot *fetch_input_tuple(AggState *aggstate);
534534
static void initialize_aggregates(AggState *aggstate,
535-
AggStatePerGroup pergroup,
535+
AggStatePerGroup *pergroups,
536536
int numReset);
537537
static void advance_transition_function(AggState *aggstate,
538538
AggStatePerTrans pertrans,
539539
AggStatePerGroup pergroupstate);
540-
static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup,
541-
AggStatePerGroup *pergroups);
540+
static void advance_aggregates(AggState *aggstate,
541+
AggStatePerGroup *sort_pergroups,
542+
AggStatePerGroup *hash_pergroups);
542543
static void advance_combine_function(AggState *aggstate,
543544
AggStatePerTrans pertrans,
544545
AggStatePerGroup pergroupstate);
@@ -793,14 +794,16 @@ initialize_aggregate(AggState *aggstate, AggStatePerTrans pertrans,
793794
* If there are multiple grouping sets, we initialize only the first numReset
794795
* of them (the grouping sets are ordered so that the most specific one, which
795796
* is reset most often, is first). As a convenience, if numReset is 0, we
796-
* reinitialize all sets. numReset is -1 to initialize a hashtable entry, in
797-
* which case the caller must have used select_current_set appropriately.
797+
* reinitialize all sets.
798+
*
799+
* NB: This cannot be used for hash aggregates, as for those the grouping set
800+
* number has to be specified from further up.
798801
*
799802
* When called, CurrentMemoryContext should be the per-query context.
800803
*/
801804
static void
802805
initialize_aggregates(AggState *aggstate,
803-
AggStatePerGroup pergroup,
806+
AggStatePerGroup *pergroups,
804807
int numReset)
805808
{
806809
int transno;
@@ -812,30 +815,18 @@ initialize_aggregates(AggState *aggstate,
812815
if (numReset == 0)
813816
numReset = numGroupingSets;
814817

815-
for (transno = 0; transno < numTrans; transno++)
818+
for (setno = 0; setno < numReset; setno++)
816819
{
817-
AggStatePerTrans pertrans = &transstates[transno];
818-
819-
if (numReset < 0)
820-
{
821-
AggStatePerGroup pergroupstate;
820+
AggStatePerGroup pergroup = pergroups[setno];
822821

823-
pergroupstate = &pergroup[transno];
822+
select_current_set(aggstate, setno, false);
824823

825-
initialize_aggregate(aggstate, pertrans, pergroupstate);
826-
}
827-
else
824+
for (transno = 0; transno < numTrans; transno++)
828825
{
829-
for (setno = 0; setno < numReset; setno++)
830-
{
831-
AggStatePerGroup pergroupstate;
832-
833-
pergroupstate = &pergroup[transno + (setno * numTrans)];
826+
AggStatePerTrans pertrans = &transstates[transno];
827+
AggStatePerGroup pergroupstate = &pergroup[transno];
834828

835-
select_current_set(aggstate, setno, false);
836-
837-
initialize_aggregate(aggstate, pertrans, pergroupstate);
838-
}
829+
initialize_aggregate(aggstate, pertrans, pergroupstate);
839830
}
840831
}
841832
}
@@ -976,7 +967,9 @@ advance_transition_function(AggState *aggstate,
976967
* When called, CurrentMemoryContext should be the per-query context.
977968
*/
978969
static void
979-
advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGroup *pergroups)
970+
advance_aggregates(AggState *aggstate,
971+
AggStatePerGroup *sort_pergroups,
972+
AggStatePerGroup *hash_pergroups)
980973
{
981974
int transno;
982975
int setno = 0;
@@ -1019,7 +1012,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGro
10191012
{
10201013
/* DISTINCT and/or ORDER BY case */
10211014
Assert(slot->tts_nvalid >= (pertrans->numInputs + inputoff));
1022-
Assert(!pergroups);
1015+
Assert(!hash_pergroups);
10231016

10241017
/*
10251018
* If the transfn is strict, we want to check for nullity before
@@ -1090,7 +1083,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGro
10901083
fcinfo->argnull[i + 1] = slot->tts_isnull[i + inputoff];
10911084
}
10921085

1093-
if (pergroup)
1086+
if (sort_pergroups)
10941087
{
10951088
/* advance transition states for ordered grouping */
10961089

@@ -1100,13 +1093,13 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGro
11001093

11011094
select_current_set(aggstate, setno, false);
11021095

1103-
pergroupstate = &pergroup[transno + (setno * numTrans)];
1096+
pergroupstate = &sort_pergroups[setno][transno];
11041097

11051098
advance_transition_function(aggstate, pertrans, pergroupstate);
11061099
}
11071100
}
11081101

1109-
if (pergroups)
1102+
if (hash_pergroups)
11101103
{
11111104
/* advance transition states for hashed grouping */
11121105

@@ -1116,7 +1109,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGro
11161109

11171110
select_current_set(aggstate, setno, true);
11181111

1119-
pergroupstate = &pergroups[setno][transno];
1112+
pergroupstate = &hash_pergroups[setno][transno];
11201113

11211114
advance_transition_function(aggstate, pertrans, pergroupstate);
11221115
}
@@ -2095,12 +2088,25 @@ lookup_hash_entry(AggState *aggstate)
20952088

20962089
if (isnew)
20972090
{
2098-
entry->additional = (AggStatePerGroup)
2091+
AggStatePerGroup pergroup;
2092+
int transno;
2093+
2094+
pergroup = (AggStatePerGroup)
20992095
MemoryContextAlloc(perhash->hashtable->tablecxt,
21002096
sizeof(AggStatePerGroupData) * aggstate->numtrans);
2101-
/* initialize aggregates for new tuple group */
2102-
initialize_aggregates(aggstate, (AggStatePerGroup) entry->additional,
2103-
-1);
2097+
entry->additional = pergroup;
2098+
2099+
/*
2100+
* Initialize aggregates for new tuple group, lookup_hash_entries()
2101+
* already has selected the relevant grouping set.
2102+
*/
2103+
for (transno = 0; transno < aggstate->numtrans; transno++)
2104+
{
2105+
AggStatePerTrans pertrans = &aggstate->pertrans[transno];
2106+
AggStatePerGroup pergroupstate = &pergroup[transno];
2107+
2108+
initialize_aggregate(aggstate, pertrans, pergroupstate);
2109+
}
21042110
}
21052111

21062112
return entry;
@@ -2184,7 +2190,7 @@ agg_retrieve_direct(AggState *aggstate)
21842190
ExprContext *econtext;
21852191
ExprContext *tmpcontext;
21862192
AggStatePerAgg peragg;
2187-
AggStatePerGroup pergroup;
2193+
AggStatePerGroup *pergroups;
21882194
AggStatePerGroup *hash_pergroups = NULL;
21892195
TupleTableSlot *outerslot;
21902196
TupleTableSlot *firstSlot;
@@ -2207,7 +2213,7 @@ agg_retrieve_direct(AggState *aggstate)
22072213
tmpcontext = aggstate->tmpcontext;
22082214

22092215
peragg = aggstate->peragg;
2210-
pergroup = aggstate->pergroup;
2216+
pergroups = aggstate->pergroups;
22112217
firstSlot = aggstate->ss.ss_ScanTupleSlot;
22122218

22132219
/*
@@ -2409,7 +2415,7 @@ agg_retrieve_direct(AggState *aggstate)
24092415
/*
24102416
* Initialize working state for a new input tuple group.
24112417
*/
2412-
initialize_aggregates(aggstate, pergroup, numReset);
2418+
initialize_aggregates(aggstate, pergroups, numReset);
24132419

24142420
if (aggstate->grp_firstTuple != NULL)
24152421
{
@@ -2446,9 +2452,9 @@ agg_retrieve_direct(AggState *aggstate)
24462452
hash_pergroups = NULL;
24472453

24482454
if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
2449-
combine_aggregates(aggstate, pergroup);
2455+
combine_aggregates(aggstate, pergroups[0]);
24502456
else
2451-
advance_aggregates(aggstate, pergroup, hash_pergroups);
2457+
advance_aggregates(aggstate, pergroups, hash_pergroups);
24522458

24532459
/* Reset per-input-tuple context after each tuple */
24542460
ResetExprContext(tmpcontext);
@@ -2512,7 +2518,7 @@ agg_retrieve_direct(AggState *aggstate)
25122518

25132519
finalize_aggregates(aggstate,
25142520
peragg,
2515-
pergroup + (currentSet * aggstate->numtrans));
2521+
pergroups[currentSet]);
25162522

25172523
/*
25182524
* If there's no row to project right now, we must continue rather
@@ -2756,7 +2762,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
27562762
aggstate->curpertrans = NULL;
27572763
aggstate->input_done = false;
27582764
aggstate->agg_done = false;
2759-
aggstate->pergroup = NULL;
2765+
aggstate->pergroups = NULL;
27602766
aggstate->grp_firstTuple = NULL;
27612767
aggstate->sort_in = NULL;
27622768
aggstate->sort_out = NULL;
@@ -3052,13 +3058,16 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
30523058

30533059
if (node->aggstrategy != AGG_HASHED)
30543060
{
3055-
AggStatePerGroup pergroup;
3061+
AggStatePerGroup *pergroups;
3062+
3063+
pergroups = (AggStatePerGroup *) palloc0(sizeof(AggStatePerGroup) *
3064+
numGroupingSets);
30563065

3057-
pergroup = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
3058-
* numaggs
3059-
* numGroupingSets);
3066+
for (i = 0; i < numGroupingSets; i++)
3067+
pergroups[i] = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
3068+
* numaggs);
30603069

3061-
aggstate->pergroup = pergroup;
3070+
aggstate->pergroups = pergroups;
30623071
}
30633072

30643073
/*
@@ -4086,8 +4095,11 @@ ExecReScanAgg(AggState *node)
40864095
/*
40874096
* Reset the per-group state (in particular, mark transvalues null)
40884097
*/
4089-
MemSet(node->pergroup, 0,
4090-
sizeof(AggStatePerGroupData) * node->numaggs * numGroupingSets);
4098+
for (setno = 0; setno < numGroupingSets; setno++)
4099+
{
4100+
MemSet(node->pergroups[setno], 0,
4101+
sizeof(AggStatePerGroupData) * node->numaggs);
4102+
}
40914103

40924104
/* reset to phase 1 */
40934105
initialize_phase(node, 1);

src/include/nodes/execnodes.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -1852,13 +1852,15 @@ typedef struct AggState
18521852
Tuplesortstate *sort_out; /* input is copied here for next phase */
18531853
TupleTableSlot *sort_slot; /* slot for sort results */
18541854
/* these fields are used in AGG_PLAIN and AGG_SORTED modes: */
1855-
AggStatePerGroup pergroup; /* per-Aggref-per-group working state */
1855+
AggStatePerGroup *pergroups; /* grouping set indexed array of per-group
1856+
* pointers */
18561857
HeapTuple grp_firstTuple; /* copy of first tuple of current group */
18571858
/* these fields are used in AGG_HASHED and AGG_MIXED modes: */
18581859
bool table_filled; /* hash table filled yet? */
18591860
int num_hashes;
18601861
AggStatePerHash perhash;
1861-
AggStatePerGroup *hash_pergroup; /* array of per-group pointers */
1862+
AggStatePerGroup *hash_pergroup; /* grouping set indexed array of
1863+
* per-group pointers */
18621864
/* support for evaluation of agg input expressions: */
18631865
ProjectionInfo *combinedproj; /* projection machinery */
18641866
} AggState;

0 commit comments

Comments
 (0)