diff options
author | Andres Freund <andres@anarazel.de> | 2018-02-15 21:55:31 -0800 |
---|---|---|
committer | Andres Freund <andres@anarazel.de> | 2018-02-16 14:38:13 -0800 |
commit | bf6c614a2f2c58312b3be34a47e7fb7362e07bcb (patch) | |
tree | bbc91aed13afc3ef3b71bada700322197fe40b69 /src/backend/executor/nodeAgg.c | |
parent | ad9a274778d2d88c46b90309212b92ee7fdf9afe (diff) | |
download | postgresql-bf6c614a2f2c58312b3be34a47e7fb7362e07bcb.tar.gz postgresql-bf6c614a2f2c58312b3be34a47e7fb7362e07bcb.zip |
Do execGrouping.c via expression eval machinery, take two.
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.
Large parts of this were previously committed (773aec7aa), but the
commit contained an omission around cross-type comparisons and was
thus reverted.
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 | 145 |
1 files changed, 88 insertions, 57 deletions
diff --git a/src/backend/executor/nodeAgg.c b/src/backend/executor/nodeAgg.c index a86d4b68eac..e74b3a93911 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,9 +1277,11 @@ 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->eqfuncoids, perhash->hashfunctions, perhash->aggnode->numGroups, additionalsize, @@ -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->eqfuncoids, + &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 **) |