diff options
author | Andres Freund <andres@anarazel.de> | 2018-02-15 21:55:31 -0800 |
---|---|---|
committer | Andres Freund <andres@anarazel.de> | 2018-02-15 21:55:31 -0800 |
commit | 773aec7aa98abd38d6d9435913bb8e14e392c274 (patch) | |
tree | 149ffe4c29433a85e84e128eb47aa22f3b388853 /src/backend/executor/nodeAgg.c | |
parent | 51db0d18fbf58b0c2e5ebc2b5b2c48daf45c8d93 (diff) | |
download | postgresql-773aec7aa98abd38d6d9435913bb8e14e392c274.tar.gz postgresql-773aec7aa98abd38d6d9435913bb8e14e392c274.zip |
Do execGrouping.c via expression eval machinery.
This has a performance benefit on own, although not hugely so. The
primary benefit is that it will allow for to JIT tuple deforming and
comparator invocations.
Author: Andres Freund
Discussion: https://postgr.es/m/20171129080934.amqqkke2zjtekd4t@alap3.anarazel.de
Diffstat (limited to 'src/backend/executor/nodeAgg.c')
-rw-r--r-- | src/backend/executor/nodeAgg.c | 143 |
1 files changed, 87 insertions, 56 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index a86d4b68eac..467f8d896ec 100644 --- a/src/backend/executor/nodeAgg.c +++ b/src/backend/executor/nodeAgg.c @@ -755,7 +755,7 @@ process_ordered_aggregate_single(AggState *aggstate, ((oldIsNull && *isNull) || (!oldIsNull && !*isNull && oldAbbrevVal == newAbbrevVal && - DatumGetBool(FunctionCall2(&pertrans->equalfns[0], + DatumGetBool(FunctionCall2(&pertrans->equalfnOne, oldVal, *newVal))))) { /* equal to prior, so forget this one */ @@ -802,7 +802,7 @@ process_ordered_aggregate_multi(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroupstate) { - MemoryContext workcontext = aggstate->tmpcontext->ecxt_per_tuple_memory; + ExprContext *tmpcontext = aggstate->tmpcontext; FunctionCallInfo fcinfo = &pertrans->transfn_fcinfo; TupleTableSlot *slot1 = pertrans->sortslot; TupleTableSlot *slot2 = pertrans->uniqslot; @@ -811,6 +811,7 @@ process_ordered_aggregate_multi(AggState *aggstate, Datum newAbbrevVal = (Datum) 0; Datum oldAbbrevVal = (Datum) 0; bool haveOldValue = false; + TupleTableSlot *save = aggstate->tmpcontext->ecxt_outertuple; int i; tuplesort_performsort(pertrans->sortstates[aggstate->current_set]); @@ -824,22 +825,20 @@ process_ordered_aggregate_multi(AggState *aggstate, { CHECK_FOR_INTERRUPTS(); - /* - * Extract the first numTransInputs columns as datums to pass to the - * transfn. (This will help execTuplesMatch too, so we do it - * immediately.) - */ - slot_getsomeattrs(slot1, numTransInputs); + tmpcontext->ecxt_outertuple = slot1; + tmpcontext->ecxt_innertuple = slot2; if (numDistinctCols == 0 || !haveOldValue || newAbbrevVal != oldAbbrevVal || - !execTuplesMatch(slot1, slot2, - numDistinctCols, - pertrans->sortColIdx, - pertrans->equalfns, - workcontext)) + !ExecQual(pertrans->equalfnMulti, tmpcontext)) { + /* + * Extract the first numTransInputs columns as datums to pass to + * the transfn. + */ + slot_getsomeattrs(slot1, numTransInputs); + /* Load values into fcinfo */ /* Start from 1, since the 0th arg will be the transition value */ for (i = 0; i < numTransInputs; i++) @@ -857,15 +856,14 @@ process_ordered_aggregate_multi(AggState *aggstate, slot2 = slot1; slot1 = tmpslot; - /* avoid execTuplesMatch() calls by reusing abbreviated keys */ + /* avoid ExecQual() calls by reusing abbreviated keys */ oldAbbrevVal = newAbbrevVal; haveOldValue = true; } } - /* Reset context each time, unless execTuplesMatch did it for us */ - if (numDistinctCols == 0) - MemoryContextReset(workcontext); + /* Reset context each time */ + ResetExprContext(tmpcontext); ExecClearTuple(slot1); } @@ -875,6 +873,9 @@ process_ordered_aggregate_multi(AggState *aggstate, tuplesort_end(pertrans->sortstates[aggstate->current_set]); pertrans->sortstates[aggstate->current_set] = NULL; + + /* restore previous slot, potentially in use for grouping sets */ + tmpcontext->ecxt_outertuple = save; } /* @@ -1276,7 +1277,9 @@ build_hash_table(AggState *aggstate) Assert(perhash->aggnode->numGroups > 0); - perhash->hashtable = BuildTupleHashTable(perhash->numCols, + perhash->hashtable = BuildTupleHashTable(&aggstate->ss.ps, + perhash->hashslot->tts_tupleDescriptor, + perhash->numCols, perhash->hashGrpColIdxHash, perhash->eqfunctions, perhash->hashfunctions, @@ -1314,6 +1317,7 @@ find_hash_columns(AggState *aggstate) Bitmapset *base_colnos; List *outerTlist = outerPlanState(aggstate)->plan->targetlist; int numHashes = aggstate->num_hashes; + EState *estate = aggstate->ss.ps.state; int j; /* Find Vars that will be needed in tlist and qual */ @@ -1393,6 +1397,12 @@ find_hash_columns(AggState *aggstate) } hashDesc = ExecTypeFromTL(hashTlist, false); + + execTuplesHashPrepare(perhash->numCols, + perhash->aggnode->grpOperators, + &perhash->eqfunctions, + &perhash->hashfunctions); + perhash->hashslot = ExecAllocTableSlot(&estate->es_tupleTable); ExecSetSlotDescriptor(perhash->hashslot, hashDesc); list_free(hashTlist); @@ -1694,17 +1704,14 @@ agg_retrieve_direct(AggState *aggstate) * of the next grouping set *---------- */ + tmpcontext->ecxt_innertuple = econtext->ecxt_outertuple; if (aggstate->input_done || (node->aggstrategy != AGG_PLAIN && aggstate->projected_set != -1 && aggstate->projected_set < (numGroupingSets - 1) && nextSetSize > 0 && - !execTuplesMatch(econtext->ecxt_outertuple, - tmpcontext->ecxt_outertuple, - nextSetSize, - node->grpColIdx, - aggstate->phase->eqfunctions, - tmpcontext->ecxt_per_tuple_memory))) + !ExecQualAndReset(aggstate->phase->eqfunctions[nextSetSize - 1], + tmpcontext))) { aggstate->projected_set += 1; @@ -1847,12 +1854,9 @@ agg_retrieve_direct(AggState *aggstate) */ if (node->aggstrategy != AGG_PLAIN) { - if (!execTuplesMatch(firstSlot, - outerslot, - node->numCols, - node->grpColIdx, - aggstate->phase->eqfunctions, - tmpcontext->ecxt_per_tuple_memory)) + tmpcontext->ecxt_innertuple = firstSlot; + if (!ExecQual(aggstate->phase->eqfunctions[node->numCols - 1], + tmpcontext)) { aggstate->grp_firstTuple = ExecCopySlotTuple(outerslot); break; @@ -2078,6 +2082,7 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) AggStatePerGroup *pergroups; Plan *outerPlan; ExprContext *econtext; + TupleDesc scanDesc; int numaggs, transno, aggno; @@ -2233,9 +2238,9 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) * initialize source tuple type. */ ExecAssignScanTypeFromOuterPlan(&aggstate->ss); + scanDesc = aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor; if (node->chain) - ExecSetSlotDescriptor(aggstate->sort_slot, - aggstate->ss.ss_ScanTupleSlot->tts_tupleDescriptor); + ExecSetSlotDescriptor(aggstate->sort_slot, scanDesc); /* * Initialize result tuple type and projection info. @@ -2355,11 +2360,43 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) */ if (aggnode->aggstrategy == AGG_SORTED) { + int i = 0; + Assert(aggnode->numCols > 0); + /* + * Build a separate function for each subset of columns that + * need to be compared. + */ phasedata->eqfunctions = - execTuplesMatchPrepare(aggnode->numCols, - aggnode->grpOperators); + (ExprState **) palloc0(aggnode->numCols * sizeof(ExprState *)); + + /* for each grouping set */ + for (i = 0; i < phasedata->numsets; i++) + { + int length = phasedata->gset_lengths[i]; + + if (phasedata->eqfunctions[length - 1] != NULL) + continue; + + phasedata->eqfunctions[length - 1] = + execTuplesMatchPrepare(scanDesc, + length, + aggnode->grpColIdx, + aggnode->grpOperators, + (PlanState *) aggstate); + } + + /* and for all grouped columns, unless already computed */ + if (phasedata->eqfunctions[aggnode->numCols - 1] == NULL) + { + phasedata->eqfunctions[aggnode->numCols - 1] = + execTuplesMatchPrepare(scanDesc, + aggnode->numCols, + aggnode->grpColIdx, + aggnode->grpOperators, + (PlanState *) aggstate); + } } phasedata->aggnode = aggnode; @@ -2412,16 +2449,6 @@ ExecInitAgg(Agg *node, EState *estate, int eflags) */ if (use_hashing) { - for (i = 0; i < numHashes; ++i) - { - aggstate->perhash[i].hashslot = ExecInitExtraTupleSlot(estate); - - execTuplesHashPrepare(aggstate->perhash[i].numCols, - aggstate->perhash[i].aggnode->grpOperators, - &aggstate->perhash[i].eqfunctions, - &aggstate->perhash[i].hashfunctions); - } - /* this is an array of pointers, not structures */ aggstate->hash_pergroup = pergroups; @@ -3101,24 +3128,28 @@ build_pertrans_for_aggref(AggStatePerTrans pertrans, if (aggref->aggdistinct) { + Oid *ops; + Assert(numArguments > 0); + Assert(list_length(aggref->aggdistinct) == numDistinctCols); - /* - * We need the equal function for each DISTINCT comparison we will - * make. - */ - pertrans->equalfns = - (FmgrInfo *) palloc(numDistinctCols * sizeof(FmgrInfo)); + ops = palloc(numDistinctCols * sizeof(Oid)); i = 0; foreach(lc, aggref->aggdistinct) - { - SortGroupClause *sortcl = (SortGroupClause *) lfirst(lc); + ops[i++] = ((SortGroupClause *) lfirst(lc))->eqop; - fmgr_info(get_opcode(sortcl->eqop), &pertrans->equalfns[i]); - i++; - } - Assert(i == numDistinctCols); + /* lookup / build the necessary comparators */ + if (numDistinctCols == 1) + fmgr_info(get_opcode(ops[0]), &pertrans->equalfnOne); + else + pertrans->equalfnMulti = + execTuplesMatchPrepare(pertrans->sortdesc, + numDistinctCols, + pertrans->sortColIdx, + ops, + &aggstate->ss.ps); + pfree(ops); } pertrans->sortstates = (Tuplesortstate **) |