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 * hashfunctions: datatype-specific hashing functions to use
* nbuckets: initial estimate of hashtable size * nbuckets: initial estimate of hashtable size
* additionalsize: size of data stored in ->additional * 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 * tempcxt: short-lived context for evaluation hash and comparison functions
* *
* The function arrays may be made with execTuplesHashPrepare(). Note they * The function arrays may be made with execTuplesHashPrepare(). Note they
@ -149,13 +150,15 @@ execTuplesHashPrepare(int numCols,
* storage that will live as long as the hashtable does. * storage that will live as long as the hashtable does.
*/ */
TupleHashTable TupleHashTable
BuildTupleHashTable(PlanState *parent, BuildTupleHashTableExt(PlanState *parent,
TupleDesc inputDesc, TupleDesc inputDesc,
int numCols, AttrNumber *keyColIdx, int numCols, AttrNumber *keyColIdx,
Oid *eqfuncoids, Oid *eqfuncoids,
FmgrInfo *hashfunctions, FmgrInfo *hashfunctions,
long nbuckets, Size additionalsize, long nbuckets, Size additionalsize,
MemoryContext tablecxt, MemoryContext tempcxt, MemoryContext metacxt,
MemoryContext tablecxt,
MemoryContext tempcxt,
bool use_variable_hash_iv) bool use_variable_hash_iv)
{ {
TupleHashTable hashtable; TupleHashTable hashtable;
@ -167,8 +170,9 @@ BuildTupleHashTable(PlanState *parent,
/* Limit initial table size request to not more than work_mem */ /* Limit initial table size request to not more than work_mem */
nbuckets = Min(nbuckets, (long) ((work_mem * 1024L) / entrysize)); nbuckets = Min(nbuckets, (long) ((work_mem * 1024L) / entrysize));
hashtable = (TupleHashTable) oldcontext = MemoryContextSwitchTo(metacxt);
MemoryContextAlloc(tablecxt, sizeof(TupleHashTableData));
hashtable = (TupleHashTable) palloc(sizeof(TupleHashTableData));
hashtable->numCols = numCols; hashtable->numCols = numCols;
hashtable->keyColIdx = keyColIdx; hashtable->keyColIdx = keyColIdx;
@ -194,9 +198,7 @@ BuildTupleHashTable(PlanState *parent,
else else
hashtable->hash_iv = 0; hashtable->hash_iv = 0;
hashtable->hashtab = tuplehash_create(tablecxt, nbuckets, hashtable); hashtable->hashtab = tuplehash_create(metacxt, nbuckets, hashtable);
oldcontext = MemoryContextSwitchTo(hashtable->tablecxt);
/* /*
* We copy the input tuple descriptor just for safety --- we assume all * We copy the input tuple descriptor just for safety --- we assume all
@ -223,6 +225,46 @@ BuildTupleHashTable(PlanState *parent,
return hashtable; 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 * 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. * 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, long nbuckets, Size additionalsize,
MemoryContext tablecxt, MemoryContext tablecxt,
MemoryContext tempcxt, bool use_variable_hash_iv); 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, extern TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable,
TupleTableSlot *slot, TupleTableSlot *slot,
bool *isnew); bool *isnew);
@ -136,6 +145,7 @@ extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable,
TupleTableSlot *slot, TupleTableSlot *slot,
ExprState *eqcomp, ExprState *eqcomp,
FmgrInfo *hashfunctions); FmgrInfo *hashfunctions);
extern void ResetTupleHashTable(TupleHashTable hashtable);
/* /*
* prototypes from functions in execJunk.c * prototypes from functions in execJunk.c