Save a few cycles in advance_transition_function().
Keep a pre-initialized FunctionCallInfoData in AggStatePerAggData, and re-use that at each row instead of doing InitFunctionCallInfoData each time. This saves only half a dozen assignments and maybe some stack manipulation, and yet that seems to be good for a percent or two of the overall query run time for simple aggregates such as count(*). The cost is that the FunctionCallInfoData (which is about a kilobyte, on 64-bit machines) stays allocated for the duration of the query instead of being short-lived stack data. But we're already paying an equivalent space cost for each regular FuncExpr or OpExpr node, so I don't feel bad about paying it for aggregate functions. The code seems a little cleaner this way too, since the number of things passed to advance_transition_function decreases.
This commit is contained in:
parent
d59ff6c110
commit
e6336b8b57
|
@ -235,6 +235,14 @@ typedef struct AggStatePerAggData
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Tuplesortstate *sortstate; /* sort object, if DISTINCT or ORDER BY */
|
Tuplesortstate *sortstate; /* sort object, if DISTINCT or ORDER BY */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This field is a pre-initialized FunctionCallInfo struct used for
|
||||||
|
* calling this aggregate's transfn. We save a few cycles per row by not
|
||||||
|
* re-initializing the unchanging fields; which isn't much, but it seems
|
||||||
|
* worth the extra space consumption.
|
||||||
|
*/
|
||||||
|
FunctionCallInfoData transfn_fcinfo;
|
||||||
} AggStatePerAggData;
|
} AggStatePerAggData;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -290,8 +298,7 @@ static void initialize_aggregates(AggState *aggstate,
|
||||||
AggStatePerGroup pergroup);
|
AggStatePerGroup pergroup);
|
||||||
static void advance_transition_function(AggState *aggstate,
|
static void advance_transition_function(AggState *aggstate,
|
||||||
AggStatePerAgg peraggstate,
|
AggStatePerAgg peraggstate,
|
||||||
AggStatePerGroup pergroupstate,
|
AggStatePerGroup pergroupstate);
|
||||||
FunctionCallInfoData *fcinfo);
|
|
||||||
static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup);
|
static void advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup);
|
||||||
static void process_ordered_aggregate_single(AggState *aggstate,
|
static void process_ordered_aggregate_single(AggState *aggstate,
|
||||||
AggStatePerAgg peraggstate,
|
AggStatePerAgg peraggstate,
|
||||||
|
@ -399,21 +406,20 @@ initialize_aggregates(AggState *aggstate,
|
||||||
* Given new input value(s), advance the transition function of an aggregate.
|
* Given new input value(s), advance the transition function of an aggregate.
|
||||||
*
|
*
|
||||||
* The new values (and null flags) have been preloaded into argument positions
|
* The new values (and null flags) have been preloaded into argument positions
|
||||||
* 1 and up in fcinfo, so that we needn't copy them again to pass to the
|
* 1 and up in peraggstate->transfn_fcinfo, so that we needn't copy them again
|
||||||
* transition function. No other fields of fcinfo are assumed valid.
|
* to pass to the transition function. We also expect that the static fields
|
||||||
|
* of the fcinfo are already initialized; that was done by ExecInitAgg().
|
||||||
*
|
*
|
||||||
* It doesn't matter which memory context this is called in.
|
* It doesn't matter which memory context this is called in.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
advance_transition_function(AggState *aggstate,
|
advance_transition_function(AggState *aggstate,
|
||||||
AggStatePerAgg peraggstate,
|
AggStatePerAgg peraggstate,
|
||||||
AggStatePerGroup pergroupstate,
|
AggStatePerGroup pergroupstate)
|
||||||
FunctionCallInfoData *fcinfo)
|
|
||||||
{
|
{
|
||||||
int numTransInputs = peraggstate->numTransInputs;
|
FunctionCallInfo fcinfo = &peraggstate->transfn_fcinfo;
|
||||||
MemoryContext oldContext;
|
MemoryContext oldContext;
|
||||||
Datum newVal;
|
Datum newVal;
|
||||||
int i;
|
|
||||||
|
|
||||||
if (peraggstate->transfn.fn_strict)
|
if (peraggstate->transfn.fn_strict)
|
||||||
{
|
{
|
||||||
|
@ -421,6 +427,9 @@ advance_transition_function(AggState *aggstate,
|
||||||
* For a strict transfn, nothing happens when there's a NULL input; we
|
* For a strict transfn, nothing happens when there's a NULL input; we
|
||||||
* just keep the prior transValue.
|
* just keep the prior transValue.
|
||||||
*/
|
*/
|
||||||
|
int numTransInputs = peraggstate->numTransInputs;
|
||||||
|
int i;
|
||||||
|
|
||||||
for (i = 1; i <= numTransInputs; i++)
|
for (i = 1; i <= numTransInputs; i++)
|
||||||
{
|
{
|
||||||
if (fcinfo->argnull[i])
|
if (fcinfo->argnull[i])
|
||||||
|
@ -467,12 +476,9 @@ advance_transition_function(AggState *aggstate,
|
||||||
/*
|
/*
|
||||||
* OK to call the transition function
|
* OK to call the transition function
|
||||||
*/
|
*/
|
||||||
InitFunctionCallInfoData(*fcinfo, &(peraggstate->transfn),
|
|
||||||
numTransInputs + 1,
|
|
||||||
peraggstate->aggCollation,
|
|
||||||
(void *) aggstate, NULL);
|
|
||||||
fcinfo->arg[0] = pergroupstate->transValue;
|
fcinfo->arg[0] = pergroupstate->transValue;
|
||||||
fcinfo->argnull[0] = pergroupstate->transValueIsNull;
|
fcinfo->argnull[0] = pergroupstate->transValueIsNull;
|
||||||
|
fcinfo->isnull = false; /* just in case transfn doesn't set it */
|
||||||
|
|
||||||
newVal = FunctionCallInvoke(fcinfo);
|
newVal = FunctionCallInvoke(fcinfo);
|
||||||
|
|
||||||
|
@ -574,19 +580,18 @@ advance_aggregates(AggState *aggstate, AggStatePerGroup pergroup)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* We can apply the transition function immediately */
|
/* We can apply the transition function immediately */
|
||||||
FunctionCallInfoData fcinfo;
|
FunctionCallInfo fcinfo = &peraggstate->transfn_fcinfo;
|
||||||
|
|
||||||
/* Load values into fcinfo */
|
/* Load values into fcinfo */
|
||||||
/* Start from 1, since the 0th arg will be the transition value */
|
/* Start from 1, since the 0th arg will be the transition value */
|
||||||
Assert(slot->tts_nvalid >= numTransInputs);
|
Assert(slot->tts_nvalid >= numTransInputs);
|
||||||
for (i = 0; i < numTransInputs; i++)
|
for (i = 0; i < numTransInputs; i++)
|
||||||
{
|
{
|
||||||
fcinfo.arg[i + 1] = slot->tts_values[i];
|
fcinfo->arg[i + 1] = slot->tts_values[i];
|
||||||
fcinfo.argnull[i + 1] = slot->tts_isnull[i];
|
fcinfo->argnull[i + 1] = slot->tts_isnull[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
advance_transition_function(aggstate, peraggstate, pergroupstate,
|
advance_transition_function(aggstate, peraggstate, pergroupstate);
|
||||||
&fcinfo);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -622,17 +627,17 @@ process_ordered_aggregate_single(AggState *aggstate,
|
||||||
MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory;
|
MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory;
|
||||||
MemoryContext oldContext;
|
MemoryContext oldContext;
|
||||||
bool isDistinct = (peraggstate->numDistinctCols > 0);
|
bool isDistinct = (peraggstate->numDistinctCols > 0);
|
||||||
|
FunctionCallInfo fcinfo = &peraggstate->transfn_fcinfo;
|
||||||
Datum *newVal;
|
Datum *newVal;
|
||||||
bool *isNull;
|
bool *isNull;
|
||||||
FunctionCallInfoData fcinfo;
|
|
||||||
|
|
||||||
Assert(peraggstate->numDistinctCols < 2);
|
Assert(peraggstate->numDistinctCols < 2);
|
||||||
|
|
||||||
tuplesort_performsort(peraggstate->sortstate);
|
tuplesort_performsort(peraggstate->sortstate);
|
||||||
|
|
||||||
/* Load the column into argument 1 (arg 0 will be transition value) */
|
/* Load the column into argument 1 (arg 0 will be transition value) */
|
||||||
newVal = fcinfo.arg + 1;
|
newVal = fcinfo->arg + 1;
|
||||||
isNull = fcinfo.argnull + 1;
|
isNull = fcinfo->argnull + 1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: if input type is pass-by-ref, the datums returned by the sort are
|
* Note: if input type is pass-by-ref, the datums returned by the sort are
|
||||||
|
@ -668,8 +673,7 @@ process_ordered_aggregate_single(AggState *aggstate,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
advance_transition_function(aggstate, peraggstate, pergroupstate,
|
advance_transition_function(aggstate, peraggstate, pergroupstate);
|
||||||
&fcinfo);
|
|
||||||
/* forget the old value, if any */
|
/* forget the old value, if any */
|
||||||
if (!oldIsNull && !peraggstate->inputtypeByVal)
|
if (!oldIsNull && !peraggstate->inputtypeByVal)
|
||||||
pfree(DatumGetPointer(oldVal));
|
pfree(DatumGetPointer(oldVal));
|
||||||
|
@ -704,7 +708,7 @@ process_ordered_aggregate_multi(AggState *aggstate,
|
||||||
AggStatePerGroup pergroupstate)
|
AggStatePerGroup pergroupstate)
|
||||||
{
|
{
|
||||||
MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory;
|
MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory;
|
||||||
FunctionCallInfoData fcinfo;
|
FunctionCallInfo fcinfo = &peraggstate->transfn_fcinfo;
|
||||||
TupleTableSlot *slot1 = peraggstate->evalslot;
|
TupleTableSlot *slot1 = peraggstate->evalslot;
|
||||||
TupleTableSlot *slot2 = peraggstate->uniqslot;
|
TupleTableSlot *slot2 = peraggstate->uniqslot;
|
||||||
int numTransInputs = peraggstate->numTransInputs;
|
int numTransInputs = peraggstate->numTransInputs;
|
||||||
|
@ -739,12 +743,11 @@ process_ordered_aggregate_multi(AggState *aggstate,
|
||||||
/* Start from 1, since the 0th arg will be the transition value */
|
/* Start from 1, since the 0th arg will be the transition value */
|
||||||
for (i = 0; i < numTransInputs; i++)
|
for (i = 0; i < numTransInputs; i++)
|
||||||
{
|
{
|
||||||
fcinfo.arg[i + 1] = slot1->tts_values[i];
|
fcinfo->arg[i + 1] = slot1->tts_values[i];
|
||||||
fcinfo.argnull[i + 1] = slot1->tts_isnull[i];
|
fcinfo->argnull[i + 1] = slot1->tts_isnull[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
advance_transition_function(aggstate, peraggstate, pergroupstate,
|
advance_transition_function(aggstate, peraggstate, pergroupstate);
|
||||||
&fcinfo);
|
|
||||||
|
|
||||||
if (numDistinctCols > 0)
|
if (numDistinctCols > 0)
|
||||||
{
|
{
|
||||||
|
@ -1799,6 +1802,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
||||||
&transfnexpr,
|
&transfnexpr,
|
||||||
&finalfnexpr);
|
&finalfnexpr);
|
||||||
|
|
||||||
|
/* set up infrastructure for calling the transfn and finalfn */
|
||||||
fmgr_info(transfn_oid, &peraggstate->transfn);
|
fmgr_info(transfn_oid, &peraggstate->transfn);
|
||||||
fmgr_info_set_expr((Node *) transfnexpr, &peraggstate->transfn);
|
fmgr_info_set_expr((Node *) transfnexpr, &peraggstate->transfn);
|
||||||
|
|
||||||
|
@ -1810,6 +1814,13 @@ ExecInitAgg(Agg *node, EState *estate, int eflags)
|
||||||
|
|
||||||
peraggstate->aggCollation = aggref->inputcollid;
|
peraggstate->aggCollation = aggref->inputcollid;
|
||||||
|
|
||||||
|
InitFunctionCallInfoData(peraggstate->transfn_fcinfo,
|
||||||
|
&peraggstate->transfn,
|
||||||
|
peraggstate->numTransInputs + 1,
|
||||||
|
peraggstate->aggCollation,
|
||||||
|
(void *) aggstate, NULL);
|
||||||
|
|
||||||
|
/* get info about relevant datatypes */
|
||||||
get_typlenbyval(aggref->aggtype,
|
get_typlenbyval(aggref->aggtype,
|
||||||
&peraggstate->resulttypeLen,
|
&peraggstate->resulttypeLen,
|
||||||
&peraggstate->resulttypeByVal);
|
&peraggstate->resulttypeByVal);
|
||||||
|
|
Loading…
Reference in New Issue