mirror of
https://github.com/postgres/postgres.git
synced 2025-06-05 23:56:58 +03:00
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/20171128003121.nmxbm2ounxzb6n2t@alap3.anarazel.de
This commit is contained in:
parent
5dc692f78d
commit
f9ccf92e16
@ -532,13 +532,14 @@ static void select_current_set(AggState *aggstate, int setno, bool is_hash);
|
|||||||
static void initialize_phase(AggState *aggstate, int newphase);
|
static void initialize_phase(AggState *aggstate, int newphase);
|
||||||
static TupleTableSlot *fetch_input_tuple(AggState *aggstate);
|
static TupleTableSlot *fetch_input_tuple(AggState *aggstate);
|
||||||
static void initialize_aggregates(AggState *aggstate,
|
static void initialize_aggregates(AggState *aggstate,
|
||||||
AggStatePerGroup pergroup,
|
AggStatePerGroup *pergroups,
|
||||||
int numReset);
|
int numReset);
|
||||||
static void advance_transition_function(AggState *aggstate,
|
static void advance_transition_function(AggState *aggstate,
|
||||||
AggStatePerTrans pertrans,
|
AggStatePerTrans pertrans,
|
||||||
AggStatePerGroup pergroupstate);
|
AggStatePerGroup pergroupstate);
|
||||||
static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup,
|
static void advance_aggregates(AggState *aggstate,
|
||||||
AggStatePerGroup *pergroups);
|
AggStatePerGroup *sort_pergroups,
|
||||||
|
AggStatePerGroup *hash_pergroups);
|
||||||
static void advance_combine_function(AggState *aggstate,
|
static void advance_combine_function(AggState *aggstate,
|
||||||
AggStatePerTrans pertrans,
|
AggStatePerTrans pertrans,
|
||||||
AggStatePerGroup pergroupstate);
|
AggStatePerGroup pergroupstate);
|
||||||
@ -793,14 +794,16 @@ initialize_aggregate(AggState *aggstate, AggStatePerTrans pertrans,
|
|||||||
* If there are multiple grouping sets, we initialize only the first numReset
|
* If there are multiple grouping sets, we initialize only the first numReset
|
||||||
* of them (the grouping sets are ordered so that the most specific one, which
|
* of them (the grouping sets are ordered so that the most specific one, which
|
||||||
* is reset most often, is first). As a convenience, if numReset is 0, we
|
* is reset most often, is first). As a convenience, if numReset is 0, we
|
||||||
* reinitialize all sets. numReset is -1 to initialize a hashtable entry, in
|
* reinitialize all sets.
|
||||||
* which case the caller must have used select_current_set appropriately.
|
*
|
||||||
|
* NB: This cannot be used for hash aggregates, as for those the grouping set
|
||||||
|
* number has to be specified from further up.
|
||||||
*
|
*
|
||||||
* When called, CurrentMemoryContext should be the per-query context.
|
* When called, CurrentMemoryContext should be the per-query context.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
initialize_aggregates(AggState *aggstate,
|
initialize_aggregates(AggState *aggstate,
|
||||||
AggStatePerGroup pergroup,
|
AggStatePerGroup *pergroups,
|
||||||
int numReset)
|
int numReset)
|
||||||
{
|
{
|
||||||
int transno;
|
int transno;
|
||||||
@ -812,33 +815,21 @@ initialize_aggregates(AggState *aggstate,
|
|||||||
if (numReset == 0)
|
if (numReset == 0)
|
||||||
numReset = numGroupingSets;
|
numReset = numGroupingSets;
|
||||||
|
|
||||||
for (transno = 0; transno < numTrans; transno++)
|
|
||||||
{
|
|
||||||
AggStatePerTrans pertrans = &transstates[transno];
|
|
||||||
|
|
||||||
if (numReset < 0)
|
|
||||||
{
|
|
||||||
AggStatePerGroup pergroupstate;
|
|
||||||
|
|
||||||
pergroupstate = &pergroup[transno];
|
|
||||||
|
|
||||||
initialize_aggregate(aggstate, pertrans, pergroupstate);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (setno = 0; setno < numReset; setno++)
|
for (setno = 0; setno < numReset; setno++)
|
||||||
{
|
{
|
||||||
AggStatePerGroup pergroupstate;
|
AggStatePerGroup pergroup = pergroups[setno];
|
||||||
|
|
||||||
pergroupstate = &pergroup[transno + (setno * numTrans)];
|
|
||||||
|
|
||||||
select_current_set(aggstate, setno, false);
|
select_current_set(aggstate, setno, false);
|
||||||
|
|
||||||
|
for (transno = 0; transno < numTrans; transno++)
|
||||||
|
{
|
||||||
|
AggStatePerTrans pertrans = &transstates[transno];
|
||||||
|
AggStatePerGroup pergroupstate = &pergroup[transno];
|
||||||
|
|
||||||
initialize_aggregate(aggstate, pertrans, pergroupstate);
|
initialize_aggregate(aggstate, pertrans, pergroupstate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given new input value(s), advance the transition function of one aggregate
|
* Given new input value(s), advance the transition function of one aggregate
|
||||||
@ -976,7 +967,9 @@ advance_transition_function(AggState *aggstate,
|
|||||||
* When called, CurrentMemoryContext should be the per-query context.
|
* When called, CurrentMemoryContext should be the per-query context.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGroup *pergroups)
|
advance_aggregates(AggState *aggstate,
|
||||||
|
AggStatePerGroup *sort_pergroups,
|
||||||
|
AggStatePerGroup *hash_pergroups)
|
||||||
{
|
{
|
||||||
int transno;
|
int transno;
|
||||||
int setno = 0;
|
int setno = 0;
|
||||||
@ -1019,7 +1012,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGro
|
|||||||
{
|
{
|
||||||
/* DISTINCT and/or ORDER BY case */
|
/* DISTINCT and/or ORDER BY case */
|
||||||
Assert(slot->tts_nvalid >= (pertrans->numInputs + inputoff));
|
Assert(slot->tts_nvalid >= (pertrans->numInputs + inputoff));
|
||||||
Assert(!pergroups);
|
Assert(!hash_pergroups);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the transfn is strict, we want to check for nullity before
|
* If the transfn is strict, we want to check for nullity before
|
||||||
@ -1090,7 +1083,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGro
|
|||||||
fcinfo->argnull[i + 1] = slot->tts_isnull[i + inputoff];
|
fcinfo->argnull[i + 1] = slot->tts_isnull[i + inputoff];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pergroup)
|
if (sort_pergroups)
|
||||||
{
|
{
|
||||||
/* advance transition states for ordered grouping */
|
/* advance transition states for ordered grouping */
|
||||||
|
|
||||||
@ -1100,13 +1093,13 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGro
|
|||||||
|
|
||||||
select_current_set(aggstate, setno, false);
|
select_current_set(aggstate, setno, false);
|
||||||
|
|
||||||
pergroupstate = &pergroup[transno + (setno * numTrans)];
|
pergroupstate = &sort_pergroups[setno][transno];
|
||||||
|
|
||||||
advance_transition_function(aggstate, pertrans, pergroupstate);
|
advance_transition_function(aggstate, pertrans, pergroupstate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pergroups)
|
if (hash_pergroups)
|
||||||
{
|
{
|
||||||
/* advance transition states for hashed grouping */
|
/* advance transition states for hashed grouping */
|
||||||
|
|
||||||
@ -1116,7 +1109,7 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup, AggStatePerGro
|
|||||||
|
|
||||||
select_current_set(aggstate, setno, true);
|
select_current_set(aggstate, setno, true);
|
||||||
|
|
||||||
pergroupstate = &pergroups[setno][transno];
|
pergroupstate = &hash_pergroups[setno][transno];
|
||||||
|
|
||||||
advance_transition_function(aggstate, pertrans, pergroupstate);
|
advance_transition_function(aggstate, pertrans, pergroupstate);
|
||||||
}
|
}
|
||||||
@ -2095,12 +2088,25 @@ lookup_hash_entry(AggState *aggstate)
|
|||||||
|
|
||||||
if (isnew)
|
if (isnew)
|
||||||
{
|
{
|
||||||
entry->additional = (AggStatePerGroup)
|
AggStatePerGroup pergroup;
|
||||||
|
int transno;
|
||||||
|
|
||||||
|
pergroup = (AggStatePerGroup)
|
||||||
MemoryContextAlloc(perhash->hashtable->tablecxt,
|
MemoryContextAlloc(perhash->hashtable->tablecxt,
|
||||||
sizeof(AggStatePerGroupData) * aggstate->numtrans);
|
sizeof(AggStatePerGroupData) * aggstate->numtrans);
|
||||||
/* initialize aggregates for new tuple group */
|
entry->additional = pergroup;
|
||||||
initialize_aggregates(aggstate, (AggStatePerGroup) entry->additional,
|
|
||||||
-1);
|
/*
|
||||||
|
* Initialize aggregates for new tuple group, lookup_hash_entries()
|
||||||
|
* already has selected the relevant grouping set.
|
||||||
|
*/
|
||||||
|
for (transno = 0; transno < aggstate->numtrans; transno++)
|
||||||
|
{
|
||||||
|
AggStatePerTrans pertrans = &aggstate->pertrans[transno];
|
||||||
|
AggStatePerGroup pergroupstate = &pergroup[transno];
|
||||||
|
|
||||||
|
initialize_aggregate(aggstate, pertrans, pergroupstate);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return entry;
|
return entry;
|
||||||
@ -2184,7 +2190,7 @@ agg_retrieve_direct(AggState *aggstate)
|
|||||||
ExprContext *econtext;
|
ExprContext *econtext;
|
||||||
ExprContext *tmpcontext;
|
ExprContext *tmpcontext;
|
||||||
AggStatePerAgg peragg;
|
AggStatePerAgg peragg;
|
||||||
AggStatePerGroup pergroup;
|
AggStatePerGroup *pergroups;
|
||||||
AggStatePerGroup *hash_pergroups = NULL;
|
AggStatePerGroup *hash_pergroups = NULL;
|
||||||
TupleTableSlot *outerslot;
|
TupleTableSlot *outerslot;
|
||||||
TupleTableSlot *firstSlot;
|
TupleTableSlot *firstSlot;
|
||||||
@ -2207,7 +2213,7 @@ agg_retrieve_direct(AggState *aggstate)
|
|||||||
tmpcontext = aggstate->tmpcontext;
|
tmpcontext = aggstate->tmpcontext;
|
||||||
|
|
||||||
peragg = aggstate->peragg;
|
peragg = aggstate->peragg;
|
||||||
pergroup = aggstate->pergroup;
|
pergroups = aggstate->pergroups;
|
||||||
firstSlot = aggstate->ss.ss_ScanTupleSlot;
|
firstSlot = aggstate->ss.ss_ScanTupleSlot;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2409,7 +2415,7 @@ agg_retrieve_direct(AggState *aggstate)
|
|||||||
/*
|
/*
|
||||||
* Initialize working state for a new input tuple group.
|
* Initialize working state for a new input tuple group.
|
||||||
*/
|
*/
|
||||||
initialize_aggregates(aggstate, pergroup, numReset);
|
initialize_aggregates(aggstate, pergroups, numReset);
|
||||||
|
|
||||||
if (aggstate->grp_firstTuple != NULL)
|
if (aggstate->grp_firstTuple != NULL)
|
||||||
{
|
{
|
||||||
@ -2446,9 +2452,9 @@ agg_retrieve_direct(AggState *aggstate)
|
|||||||
hash_pergroups = NULL;
|
hash_pergroups = NULL;
|
||||||
|
|
||||||
if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
|
if (DO_AGGSPLIT_COMBINE(aggstate->aggsplit))
|
||||||
combine_aggregates(aggstate, pergroup);
|
combine_aggregates(aggstate, pergroups[0]);
|
||||||
else
|
else
|
||||||
advance_aggregates(aggstate, pergroup, hash_pergroups);
|
advance_aggregates(aggstate, pergroups, hash_pergroups);
|
||||||
|
|
||||||
/* Reset per-input-tuple context after each tuple */
|
/* Reset per-input-tuple context after each tuple */
|
||||||
ResetExprContext(tmpcontext);
|
ResetExprContext(tmpcontext);
|
||||||
@ -2512,7 +2518,7 @@ agg_retrieve_direct(AggState *aggstate)
|
|||||||
|
|
||||||
finalize_aggregates(aggstate,
|
finalize_aggregates(aggstate,
|
||||||
peragg,
|
peragg,
|
||||||
pergroup + (currentSet * aggstate->numtrans));
|
pergroups[currentSet]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there's no row to project right now, we must continue rather
|
* If there's no row to project right now, we must continue rather
|
||||||
@ -2756,7 +2762,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
|||||||
aggstate->curpertrans = NULL;
|
aggstate->curpertrans = NULL;
|
||||||
aggstate->input_done = false;
|
aggstate->input_done = false;
|
||||||
aggstate->agg_done = false;
|
aggstate->agg_done = false;
|
||||||
aggstate->pergroup = NULL;
|
aggstate->pergroups = NULL;
|
||||||
aggstate->grp_firstTuple = NULL;
|
aggstate->grp_firstTuple = NULL;
|
||||||
aggstate->sort_in = NULL;
|
aggstate->sort_in = NULL;
|
||||||
aggstate->sort_out = NULL;
|
aggstate->sort_out = NULL;
|
||||||
@ -3052,13 +3058,16 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
|||||||
|
|
||||||
if (node->aggstrategy != AGG_HASHED)
|
if (node->aggstrategy != AGG_HASHED)
|
||||||
{
|
{
|
||||||
AggStatePerGroup pergroup;
|
AggStatePerGroup *pergroups;
|
||||||
|
|
||||||
pergroup = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
|
pergroups = (AggStatePerGroup *) palloc0(sizeof(AggStatePerGroup) *
|
||||||
* numaggs
|
numGroupingSets);
|
||||||
* numGroupingSets);
|
|
||||||
|
|
||||||
aggstate->pergroup = pergroup;
|
for (i = 0; i < numGroupingSets; i++)
|
||||||
|
pergroups[i] = (AggStatePerGroup) palloc0(sizeof(AggStatePerGroupData)
|
||||||
|
* numaggs);
|
||||||
|
|
||||||
|
aggstate->pergroups = pergroups;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -4086,8 +4095,11 @@ ExecReScanAgg(AggState *node)
|
|||||||
/*
|
/*
|
||||||
* Reset the per-group state (in particular, mark transvalues null)
|
* Reset the per-group state (in particular, mark transvalues null)
|
||||||
*/
|
*/
|
||||||
MemSet(node->pergroup, 0,
|
for (setno = 0; setno < numGroupingSets; setno++)
|
||||||
sizeof(AggStatePerGroupData) * node->numaggs * numGroupingSets);
|
{
|
||||||
|
MemSet(node->pergroups[setno], 0,
|
||||||
|
sizeof(AggStatePerGroupData) * node->numaggs);
|
||||||
|
}
|
||||||
|
|
||||||
/* reset to phase 1 */
|
/* reset to phase 1 */
|
||||||
initialize_phase(node, 1);
|
initialize_phase(node, 1);
|
||||||
|
@ -1852,13 +1852,15 @@ typedef struct AggState
|
|||||||
Tuplesortstate *sort_out; /* input is copied here for next phase */
|
Tuplesortstate *sort_out; /* input is copied here for next phase */
|
||||||
TupleTableSlot *sort_slot; /* slot for sort results */
|
TupleTableSlot *sort_slot; /* slot for sort results */
|
||||||
/* these fields are used in AGG_PLAIN and AGG_SORTED modes: */
|
/* these fields are used in AGG_PLAIN and AGG_SORTED modes: */
|
||||||
AggStatePerGroup pergroup; /* per-Aggref-per-group working state */
|
AggStatePerGroup *pergroups; /* grouping set indexed array of per-group
|
||||||
|
* pointers */
|
||||||
HeapTuple grp_firstTuple; /* copy of first tuple of current group */
|
HeapTuple grp_firstTuple; /* copy of first tuple of current group */
|
||||||
/* these fields are used in AGG_HASHED and AGG_MIXED modes: */
|
/* these fields are used in AGG_HASHED and AGG_MIXED modes: */
|
||||||
bool table_filled; /* hash table filled yet? */
|
bool table_filled; /* hash table filled yet? */
|
||||||
int num_hashes;
|
int num_hashes;
|
||||||
AggStatePerHash perhash;
|
AggStatePerHash perhash;
|
||||||
AggStatePerGroup *hash_pergroup; /* array of per-group pointers */
|
AggStatePerGroup *hash_pergroup; /* grouping set indexed array of
|
||||||
|
* per-group pointers */
|
||||||
/* support for evaluation of agg input expressions: */
|
/* support for evaluation of agg input expressions: */
|
||||||
ProjectionInfo *combinedproj; /* projection machinery */
|
ProjectionInfo *combinedproj; /* projection machinery */
|
||||||
} AggState;
|
} AggState;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user