Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit200f610

Browse files
committed
Fix LookupTupleHashEntryHash() pipeline-stall issue.
Refactor hash lookups in nodeAgg.c to improve performance.Author: Andres Freund and Jeff DavisDiscussion:https://postgr.es/m/20200612213715.op4ye4q7gktqvpuo%40alap3.anarazel.deBackpatch-through: 13
1 parent56788d2 commit200f610

File tree

6 files changed

+105
-101
lines changed

6 files changed

+105
-101
lines changed

‎src/backend/executor/execGrouping.c

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,11 @@
2222
#include"utils/memutils.h"
2323

2424
staticintTupleHashTableMatch(structtuplehash_hash*tb,constMinimalTupletuple1,constMinimalTupletuple2);
25-
staticuint32TupleHashTableHash_internal(structtuplehash_hash*tb,
26-
constMinimalTupletuple);
27-
staticTupleHashEntryLookupTupleHashEntry_internal(TupleHashTablehashtable,
28-
TupleTableSlot*slot,
29-
bool*isnew,uint32hash);
25+
staticinlineuint32TupleHashTableHash_internal(structtuplehash_hash*tb,
26+
constMinimalTupletuple);
27+
staticinlineTupleHashEntryLookupTupleHashEntry_internal(TupleHashTablehashtable,
28+
TupleTableSlot*slot,
29+
bool*isnew,uint32hash);
3030

3131
/*
3232
* Define parameters for tuple hash table code generation. The interface is
@@ -291,18 +291,21 @@ ResetTupleHashTable(TupleHashTable hashtable)
291291
* If isnew is NULL, we do not create new entries; we return NULL if no
292292
* match is found.
293293
*
294+
* If hash is not NULL, we set it to the calculated hash value. This allows
295+
* callers access to the hash value even if no entry is returned.
296+
*
294297
* If isnew isn't NULL, then a new entry is created if no existing entry
295298
* matches. On return, *isnew is true if the entry is newly created,
296299
* false if it existed already. ->additional_data in the new entry has
297300
* been zeroed.
298301
*/
299302
TupleHashEntry
300303
LookupTupleHashEntry(TupleHashTablehashtable,TupleTableSlot*slot,
301-
bool*isnew)
304+
bool*isnew,uint32*hash)
302305
{
303306
TupleHashEntryentry;
304307
MemoryContextoldContext;
305-
uint32hash;
308+
uint32local_hash;
306309

307310
/* Need to run the hash functions in short-lived context */
308311
oldContext=MemoryContextSwitchTo(hashtable->tempcxt);
@@ -312,8 +315,13 @@ LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
312315
hashtable->in_hash_funcs=hashtable->tab_hash_funcs;
313316
hashtable->cur_eq_func=hashtable->tab_eq_func;
314317

315-
hash=TupleHashTableHash_internal(hashtable->hashtab,NULL);
316-
entry=LookupTupleHashEntry_internal(hashtable,slot,isnew,hash);
318+
local_hash=TupleHashTableHash_internal(hashtable->hashtab,NULL);
319+
entry=LookupTupleHashEntry_internal(hashtable,slot,isnew,local_hash);
320+
321+
if (hash!=NULL)
322+
*hash=local_hash;
323+
324+
Assert(entry==NULL||entry->hash==local_hash);
317325

318326
MemoryContextSwitchTo(oldContext);
319327

@@ -362,6 +370,7 @@ LookupTupleHashEntryHash(TupleHashTable hashtable, TupleTableSlot *slot,
362370
hashtable->cur_eq_func=hashtable->tab_eq_func;
363371

364372
entry=LookupTupleHashEntry_internal(hashtable,slot,isnew,hash);
373+
Assert(entry==NULL||entry->hash==hash);
365374

366375
MemoryContextSwitchTo(oldContext);
367376

@@ -480,7 +489,7 @@ TupleHashTableHash_internal(struct tuplehash_hash *tb,
480489
* NB: This function may or may not change the memory context. Caller is
481490
* expected to change it back.
482491
*/
483-
staticTupleHashEntry
492+
staticinlineTupleHashEntry
484493
LookupTupleHashEntry_internal(TupleHashTablehashtable,TupleTableSlot*slot,
485494
bool*isnew,uint32hash)
486495
{

‎src/backend/executor/nodeAgg.c

Lines changed: 79 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,9 @@ static void finalize_partialaggregate(AggState *aggstate,
391391
AggStatePerAggperagg,
392392
AggStatePerGrouppergroupstate,
393393
Datum*resultVal,bool*resultIsNull);
394-
staticvoidprepare_hash_slot(AggState*aggstate);
394+
staticinlinevoidprepare_hash_slot(AggStatePerHashperhash,
395+
TupleTableSlot*inputslot,
396+
TupleTableSlot*hashslot);
395397
staticvoidprepare_projection_slot(AggState*aggstate,
396398
TupleTableSlot*slot,
397399
intcurrentSet);
@@ -413,8 +415,9 @@ static inthash_choose_num_partitions(uint64 input_groups,
413415
doublehashentrysize,
414416
intused_bits,
415417
int*log2_npartittions);
416-
staticAggStatePerGrouplookup_hash_entry(AggState*aggstate,uint32hash,
417-
bool*in_hash_table);
418+
staticvoidinitialize_hash_entry(AggState*aggstate,
419+
TupleHashTablehashtable,
420+
TupleHashEntryentry);
418421
staticvoidlookup_hash_entries(AggState*aggstate);
419422
staticTupleTableSlot*agg_retrieve_direct(AggState*aggstate);
420423
staticvoidagg_fill_hash_table(AggState*aggstate);
@@ -1207,12 +1210,11 @@ finalize_partialaggregate(AggState *aggstate,
12071210
* Extract the attributes that make up the grouping key into the
12081211
* hashslot. This is necessary to compute the hash or perform a lookup.
12091212
*/
1210-
staticvoid
1211-
prepare_hash_slot(AggState*aggstate)
1213+
staticinlinevoid
1214+
prepare_hash_slot(AggStatePerHashperhash,
1215+
TupleTableSlot*inputslot,
1216+
TupleTableSlot*hashslot)
12121217
{
1213-
TupleTableSlot*inputslot=aggstate->tmpcontext->ecxt_outertuple;
1214-
AggStatePerHashperhash=&aggstate->perhash[aggstate->current_set];
1215-
TupleTableSlot*hashslot=perhash->hashslot;
12161218
inti;
12171219

12181220
/* transfer just the needed columns into hashslot */
@@ -2013,75 +2015,39 @@ hash_choose_num_partitions(uint64 input_groups, double hashentrysize,
20132015
}
20142016

20152017
/*
2016-
* Find or create a hashtable entry for the tuple group containing the current
2017-
* tuple (already set in tmpcontext's outertuple slot), in the current grouping
2018-
* set (which the caller must have selected - note that initialize_aggregate
2019-
* depends on this).
2020-
*
2021-
* When called, CurrentMemoryContext should be the per-query context. The
2022-
* already-calculated hash value for the tuple must be specified.
2023-
*
2024-
* If in "spill mode", then only find existing hashtable entries; don't create
2025-
* new ones. If a tuple's group is not already present in the hash table for
2026-
* the current grouping set, assign *in_hash_table=false and the caller will
2027-
* spill it to disk.
2018+
* Initialize a freshly-created TupleHashEntry.
20282019
*/
2029-
staticAggStatePerGroup
2030-
lookup_hash_entry(AggState*aggstate,uint32hash,bool*in_hash_table)
2020+
staticvoid
2021+
initialize_hash_entry(AggState*aggstate,TupleHashTablehashtable,
2022+
TupleHashEntryentry)
20312023
{
2032-
AggStatePerHashperhash=&aggstate->perhash[aggstate->current_set];
2033-
TupleTableSlot*hashslot=perhash->hashslot;
2034-
TupleHashEntryData*entry;
2035-
boolisnew= false;
2036-
bool*p_isnew;
2037-
2038-
/* if hash table already spilled, don't create new entries */
2039-
p_isnew=aggstate->hash_spill_mode ?NULL :&isnew;
2040-
2041-
/* find or create the hashtable entry using the filtered tuple */
2042-
entry=LookupTupleHashEntryHash(perhash->hashtable,hashslot,p_isnew,
2043-
hash);
2044-
2045-
if (entry==NULL)
2046-
{
2047-
*in_hash_table= false;
2048-
returnNULL;
2049-
}
2050-
else
2051-
*in_hash_table= true;
2052-
2053-
if (isnew)
2054-
{
2055-
AggStatePerGrouppergroup;
2056-
inttransno;
2024+
AggStatePerGrouppergroup;
2025+
inttransno;
20572026

2058-
aggstate->hash_ngroups_current++;
2059-
hash_agg_check_limits(aggstate);
2027+
aggstate->hash_ngroups_current++;
2028+
hash_agg_check_limits(aggstate);
20602029

2061-
/* no need to allocate or initialize per-group state */
2062-
if (aggstate->numtrans==0)
2063-
returnNULL;
2030+
/* no need to allocate or initialize per-group state */
2031+
if (aggstate->numtrans==0)
2032+
return;
20642033

2065-
pergroup= (AggStatePerGroup)
2066-
MemoryContextAlloc(perhash->hashtable->tablecxt,
2067-
sizeof(AggStatePerGroupData)*aggstate->numtrans);
2034+
pergroup= (AggStatePerGroup)
2035+
MemoryContextAlloc(hashtable->tablecxt,
2036+
sizeof(AggStatePerGroupData)*aggstate->numtrans);
20682037

2069-
entry->additional=pergroup;
2038+
entry->additional=pergroup;
20702039

2071-
/*
2072-
* Initialize aggregates for new tuple group, lookup_hash_entries()
2073-
* already has selected the relevant grouping set.
2074-
*/
2075-
for (transno=0;transno<aggstate->numtrans;transno++)
2076-
{
2077-
AggStatePerTranspertrans=&aggstate->pertrans[transno];
2078-
AggStatePerGrouppergroupstate=&pergroup[transno];
2040+
/*
2041+
* Initialize aggregates for new tuple group, lookup_hash_entries()
2042+
* already has selected the relevant grouping set.
2043+
*/
2044+
for (transno=0;transno<aggstate->numtrans;transno++)
2045+
{
2046+
AggStatePerTranspertrans=&aggstate->pertrans[transno];
2047+
AggStatePerGrouppergroupstate=&pergroup[transno];
20792048

2080-
initialize_aggregate(aggstate,pertrans,pergroupstate);
2081-
}
2049+
initialize_aggregate(aggstate,pertrans,pergroupstate);
20822050
}
2083-
2084-
returnentry->additional;
20852051
}
20862052

20872053
/*
@@ -2106,21 +2072,37 @@ static void
21062072
lookup_hash_entries(AggState*aggstate)
21072073
{
21082074
AggStatePerGroup*pergroup=aggstate->hash_pergroup;
2075+
TupleTableSlot*outerslot=aggstate->tmpcontext->ecxt_outertuple;
21092076
intsetno;
21102077

21112078
for (setno=0;setno<aggstate->num_hashes;setno++)
21122079
{
21132080
AggStatePerHashperhash=&aggstate->perhash[setno];
2081+
TupleHashTablehashtable=perhash->hashtable;
2082+
TupleTableSlot*hashslot=perhash->hashslot;
2083+
TupleHashEntryentry;
21142084
uint32hash;
2115-
boolin_hash_table;
2085+
boolisnew= false;
2086+
bool*p_isnew;
2087+
2088+
/* if hash table already spilled, don't create new entries */
2089+
p_isnew=aggstate->hash_spill_mode ?NULL :&isnew;
21162090

21172091
select_current_set(aggstate,setno, true);
2118-
prepare_hash_slot(aggstate);
2119-
hash=TupleHashTableHash(perhash->hashtable,perhash->hashslot);
2120-
pergroup[setno]=lookup_hash_entry(aggstate,hash,&in_hash_table);
2092+
prepare_hash_slot(perhash,
2093+
outerslot,
2094+
hashslot);
2095+
2096+
entry=LookupTupleHashEntry(hashtable,hashslot,
2097+
p_isnew,&hash);
21212098

2122-
/* check to see if we need to spill the tuple for this grouping set */
2123-
if (!in_hash_table)
2099+
if (entry!=NULL)
2100+
{
2101+
if (isnew)
2102+
initialize_hash_entry(aggstate,hashtable,entry);
2103+
pergroup[setno]=entry->additional;
2104+
}
2105+
else
21242106
{
21252107
HashAggSpill*spill=&aggstate->hash_spills[setno];
21262108
TupleTableSlot*slot=aggstate->tmpcontext->ecxt_outertuple;
@@ -2131,6 +2113,7 @@ lookup_hash_entries(AggState *aggstate)
21312113
aggstate->hashentrysize);
21322114

21332115
hashagg_spill_tuple(aggstate,spill,slot,hash);
2116+
pergroup[setno]=NULL;
21342117
}
21352118
}
21362119
}
@@ -2588,6 +2571,7 @@ static bool
25882571
agg_refill_hash_table(AggState*aggstate)
25892572
{
25902573
HashAggBatch*batch;
2574+
AggStatePerHashperhash;
25912575
HashAggSpillspill;
25922576
HashTapeInfo*tapeinfo=aggstate->hash_tapeinfo;
25932577
uint64ngroups_estimate;
@@ -2639,6 +2623,8 @@ agg_refill_hash_table(AggState *aggstate)
26392623

26402624
select_current_set(aggstate,batch->setno, true);
26412625

2626+
perhash=&aggstate->perhash[aggstate->current_set];
2627+
26422628
/*
26432629
* Spilled tuples are always read back as MinimalTuples, which may be
26442630
* different from the outer plan, so recompile the aggregate expressions.
@@ -2652,27 +2638,34 @@ agg_refill_hash_table(AggState *aggstate)
26522638
HASHAGG_READ_BUFFER_SIZE);
26532639
for (;;)
26542640
{
2655-
TupleTableSlot*slot=aggstate->hash_spill_rslot;
2641+
TupleTableSlot*spillslot=aggstate->hash_spill_rslot;
2642+
TupleTableSlot*hashslot=perhash->hashslot;
2643+
TupleHashEntryentry;
26562644
MinimalTupletuple;
26572645
uint32hash;
2658-
boolin_hash_table;
2646+
boolisnew= false;
2647+
bool*p_isnew=aggstate->hash_spill_mode ?NULL :&isnew;
26592648

26602649
CHECK_FOR_INTERRUPTS();
26612650

26622651
tuple=hashagg_batch_read(batch,&hash);
26632652
if (tuple==NULL)
26642653
break;
26652654

2666-
ExecStoreMinimalTuple(tuple,slot, true);
2667-
aggstate->tmpcontext->ecxt_outertuple=slot;
2655+
ExecStoreMinimalTuple(tuple,spillslot, true);
2656+
aggstate->tmpcontext->ecxt_outertuple=spillslot;
26682657

2669-
prepare_hash_slot(aggstate);
2670-
aggstate->hash_pergroup[batch->setno]=
2671-
lookup_hash_entry(aggstate,hash,&in_hash_table);
2658+
prepare_hash_slot(perhash,
2659+
aggstate->tmpcontext->ecxt_outertuple,
2660+
hashslot);
2661+
entry=LookupTupleHashEntryHash(
2662+
perhash->hashtable,hashslot,p_isnew,hash);
26722663

2673-
if (in_hash_table)
2664+
if (entry!=NULL)
26742665
{
2675-
/* Advance the aggregates (or combine functions) */
2666+
if (isnew)
2667+
initialize_hash_entry(aggstate,perhash->hashtable,entry);
2668+
aggstate->hash_pergroup[batch->setno]=entry->additional;
26762669
advance_aggregates(aggstate);
26772670
}
26782671
else
@@ -2688,7 +2681,9 @@ agg_refill_hash_table(AggState *aggstate)
26882681
ngroups_estimate,aggstate->hashentrysize);
26892682
}
26902683
/* no memory for a new group, spill */
2691-
hashagg_spill_tuple(aggstate,&spill,slot,hash);
2684+
hashagg_spill_tuple(aggstate,&spill,spillslot,hash);
2685+
2686+
aggstate->hash_pergroup[batch->setno]=NULL;
26922687
}
26932688

26942689
/*

‎src/backend/executor/nodeRecursiveunion.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ ExecRecursiveUnion(PlanState *pstate)
9494
if (plan->numCols>0)
9595
{
9696
/* Find or build hashtable entry for this tuple's group */
97-
LookupTupleHashEntry(node->hashtable,slot,&isnew);
97+
LookupTupleHashEntry(node->hashtable,slot,&isnew,NULL);
9898
/* Must reset temp context after each hashtable lookup */
9999
MemoryContextReset(node->tempContext);
100100
/* Ignore tuple if already seen */
@@ -141,7 +141,7 @@ ExecRecursiveUnion(PlanState *pstate)
141141
if (plan->numCols>0)
142142
{
143143
/* Find or build hashtable entry for this tuple's group */
144-
LookupTupleHashEntry(node->hashtable,slot,&isnew);
144+
LookupTupleHashEntry(node->hashtable,slot,&isnew,NULL);
145145
/* Must reset temp context after each hashtable lookup */
146146
MemoryContextReset(node->tempContext);
147147
/* Ignore tuple if already seen */

‎src/backend/executor/nodeSetOp.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ setop_fill_hash_table(SetOpState *setopstate)
381381

382382
/* Find or build hashtable entry for this tuple's group */
383383
entry=LookupTupleHashEntry(setopstate->hashtable,outerslot,
384-
&isnew);
384+
&isnew,NULL);
385385

386386
/* If new tuple group, initialize counts */
387387
if (isnew)
@@ -402,7 +402,7 @@ setop_fill_hash_table(SetOpState *setopstate)
402402

403403
/* For tuples not seen previously, do not make hashtable entry */
404404
entry=LookupTupleHashEntry(setopstate->hashtable,outerslot,
405-
NULL);
405+
NULL,NULL);
406406

407407
/* Advance the counts if entry is already present */
408408
if (entry)

‎src/backend/executor/nodeSubplan.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -595,12 +595,12 @@ buildSubPlanHash(SubPlanState *node, ExprContext *econtext)
595595
*/
596596
if (slotNoNulls(slot))
597597
{
598-
(void)LookupTupleHashEntry(node->hashtable,slot,&isnew);
598+
(void)LookupTupleHashEntry(node->hashtable,slot,&isnew,NULL);
599599
node->havehashrows= true;
600600
}
601601
elseif (node->hashnulls)
602602
{
603-
(void)LookupTupleHashEntry(node->hashnulls,slot,&isnew);
603+
(void)LookupTupleHashEntry(node->hashnulls,slot,&isnew,NULL);
604604
node->havenullrows= true;
605605
}
606606

‎src/include/executor/executor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ extern TupleHashTable BuildTupleHashTableExt(PlanState *parent,
139139
MemoryContexttempcxt,booluse_variable_hash_iv);
140140
externTupleHashEntryLookupTupleHashEntry(TupleHashTablehashtable,
141141
TupleTableSlot*slot,
142-
bool*isnew);
142+
bool*isnew,uint32*hash);
143143
externuint32TupleHashTableHash(TupleHashTablehashtable,
144144
TupleTableSlot*slot);
145145
externTupleHashEntryLookupTupleHashEntryHash(TupleHashTablehashtable,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp