Allow to reset execGrouping.c style tuple hashtables.

This has the advantage that the comparator expression, the table's
slot, etc do not have to be rebuilt. Additionally the simplehash.h
hashtable within the tuple hashtable now keeps its previous size and
doesn't need to be reallocated. That both reduces allocator overhead,
and improves performance in cases where the input estimation was off
by a significant factor.

To avoid an API/ABI break, the new parameter is exposed via the new
BuildTupleHashTableExt(), and BuildTupleHashTable() now is a wrapper
around the former, that continues to allocate the table itself in the
tablecxt.

Using this fixes performance issues discovered in the two bugs
referenced. This commit however has not converted the callers, that's
done in a separate commit.

Bug: #15592 #15486
Reported-By: Jakub Janeček, Dmitry Marakasov
Author: Andres Freund
Discussion:
    https://postgr.es/m/15486-05850f065da42931@postgresql.org
    https://postgr.es/m/20190114180423.ywhdg2iagzvh43we@alap3.anarazel.de
Backpatch: 11, this is a prerequisite for other fixes
This commit is contained in:
Andres Freund 2019-02-09 00:35:57 -08:00
parent 350b0a4037
commit 6455c65882
2 changed files with 66 additions and 14 deletions

View File

@ -138,7 +138,8 @@ execTuplesHashPrepare(int numCols,
* hashfunctions: datatype-specific hashing functions to use
* nbuckets: initial estimate of hashtable size
* additionalsize: size of data stored in ->additional
* tablecxt: memory context in which to store table and table entries
* metacxt: memory context for long-lived allocation, but not per-entry data
* tablecxt: memory context in which to store table entries
* tempcxt: short-lived context for evaluation hash and comparison functions
*
* The function arrays may be made with execTuplesHashPrepare(). Note they
@ -149,14 +150,16 @@ execTuplesHashPrepare(int numCols,
* storage that will live as long as the hashtable does.
*/
TupleHashTable
BuildTupleHashTable(PlanState *parent,
TupleDesc inputDesc,
int numCols, AttrNumber *keyColIdx,
Oid *eqfuncoids,
FmgrInfo *hashfunctions,
long nbuckets, Size additionalsize,
MemoryContext tablecxt, MemoryContext tempcxt,
bool use_variable_hash_iv)
BuildTupleHashTableExt(PlanState *parent,
TupleDesc inputDesc,
int numCols, AttrNumber *keyColIdx,
Oid *eqfuncoids,
FmgrInfo *hashfunctions,
long nbuckets, Size additionalsize,
MemoryContext metacxt,
MemoryContext tablecxt,
MemoryContext tempcxt,
bool use_variable_hash_iv)
{
TupleHashTable hashtable;
Size entrysize = sizeof(TupleHashEntryData) + additionalsize;
@ -167,8 +170,9 @@ BuildTupleHashTable(PlanState *parent,
/* Limit initial table size request to not more than work_mem */
nbuckets = Min(nbuckets, (long) ((work_mem * 1024L) / entrysize));
hashtable = (TupleHashTable)
MemoryContextAlloc(tablecxt, sizeof(TupleHashTableData));
oldcontext = MemoryContextSwitchTo(metacxt);
hashtable = (TupleHashTable) palloc(sizeof(TupleHashTableData));
hashtable->numCols = numCols;
hashtable->keyColIdx = keyColIdx;
@ -194,9 +198,7 @@ BuildTupleHashTable(PlanState *parent,
else
hashtable->hash_iv = 0;
hashtable->hashtab = tuplehash_create(tablecxt, nbuckets, hashtable);
oldcontext = MemoryContextSwitchTo(hashtable->tablecxt);
hashtable->hashtab = tuplehash_create(metacxt, nbuckets, hashtable);
/*
* We copy the input tuple descriptor just for safety --- we assume all
@ -223,6 +225,46 @@ BuildTupleHashTable(PlanState *parent,
return hashtable;
}
/*
* BuildTupleHashTable is a backwards-compatibilty wrapper for
* BuildTupleHashTableExt(), that allocates the hashtable's metadata in
* tablecxt. Note that hashtables created this way cannot be reset leak-free
* with ResetTupleHashTable().
*/
TupleHashTable
BuildTupleHashTable(PlanState *parent,
TupleDesc inputDesc,
int numCols, AttrNumber *keyColIdx,
Oid *eqfuncoids,
FmgrInfo *hashfunctions,
long nbuckets, Size additionalsize,
MemoryContext tablecxt,
MemoryContext tempcxt,
bool use_variable_hash_iv)
{
return BuildTupleHashTableExt(parent,
inputDesc,
numCols, keyColIdx,
eqfuncoids,
hashfunctions,
nbuckets, additionalsize,
tablecxt,
tablecxt,
tempcxt,
use_variable_hash_iv);
}
/*
* Reset contents of the hashtable to be empty, preserving all the non-content
* state. Note that the tablecxt passed to BuildTupleHashTableExt() should
* also be reset, otherwise there will be leaks.
*/
void
ResetTupleHashTable(TupleHashTable hashtable)
{
tuplehash_reset(hashtable->hashtab);
}
/*
* Find or create a hashtable entry for the tuple group containing the
* given tuple. The tuple must be the same type as the hashtable entries.

View File

@ -129,6 +129,15 @@ extern TupleHashTable BuildTupleHashTable(PlanState *parent,
long nbuckets, Size additionalsize,
MemoryContext tablecxt,
MemoryContext tempcxt, bool use_variable_hash_iv);
extern TupleHashTable BuildTupleHashTableExt(PlanState *parent,
TupleDesc inputDesc,
int numCols, AttrNumber *keyColIdx,
Oid *eqfuncoids,
FmgrInfo *hashfunctions,
long nbuckets, Size additionalsize,
MemoryContext metacxt,
MemoryContext tablecxt,
MemoryContext tempcxt, bool use_variable_hash_iv);
extern TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable,
TupleTableSlot *slot,
bool *isnew);
@ -136,6 +145,7 @@ extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable,
TupleTableSlot *slot,
ExprState *eqcomp,
FmgrInfo *hashfunctions);
extern void ResetTupleHashTable(TupleHashTable hashtable);
/*
* prototypes from functions in execJunk.c