1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-14 08:21:07 +03:00

Revert "TupleHashTable: store additional data along with tuple."

This reverts commit e0ece2a981 due to
performance regressions.

Reported-by: David Rowley
This commit is contained in:
Jeff Davis
2025-01-13 14:14:07 -08:00
parent af2317652d
commit b4a07f532b
6 changed files with 31 additions and 78 deletions

View File

@ -20,13 +20,6 @@
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
struct TupleHashEntryData
{
MinimalTuple firstTuple; /* copy of first tuple in this group */
uint32 status; /* hash status */
uint32 hash; /* hash value (cached) */
};
static int TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tuple1, const MinimalTuple tuple2); static int TupleHashTableMatch(struct tuplehash_hash *tb, const MinimalTuple tuple1, const MinimalTuple tuple2);
static inline uint32 TupleHashTableHash_internal(struct tuplehash_hash *tb, static inline uint32 TupleHashTableHash_internal(struct tuplehash_hash *tb,
const MinimalTuple tuple); const MinimalTuple tuple);
@ -203,7 +196,6 @@ BuildTupleHashTable(PlanState *parent,
hashtable->tab_collations = collations; hashtable->tab_collations = collations;
hashtable->tablecxt = tablecxt; hashtable->tablecxt = tablecxt;
hashtable->tempcxt = tempcxt; hashtable->tempcxt = tempcxt;
hashtable->additionalsize = additionalsize;
hashtable->tableslot = NULL; /* will be made on first lookup */ hashtable->tableslot = NULL; /* will be made on first lookup */
hashtable->inputslot = NULL; hashtable->inputslot = NULL;
hashtable->in_hash_expr = NULL; hashtable->in_hash_expr = NULL;
@ -281,15 +273,6 @@ ResetTupleHashTable(TupleHashTable hashtable)
tuplehash_reset(hashtable->hashtab); tuplehash_reset(hashtable->hashtab);
} }
/*
* Return size of the hash bucket. Useful for estimating memory usage.
*/
size_t
TupleHashEntrySize(void)
{
return sizeof(TupleHashEntryData);
}
/* /*
* 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.
@ -356,24 +339,6 @@ TupleHashTableHash(TupleHashTable hashtable, TupleTableSlot *slot)
return hash; return hash;
} }
MinimalTuple
TupleHashEntryGetTuple(TupleHashEntry entry)
{
return entry->firstTuple;
}
/*
* Get a pointer into the additional space allocated for this entry. The
* amount of space available is the additionalsize specified to
* BuildTupleHashTable(). If additionalsize was specified as zero, no
* additional space is available and this function should not be called.
*/
void *
TupleHashEntryGetAdditional(TupleHashEntry entry)
{
return (char *) entry->firstTuple + MAXALIGN(entry->firstTuple->t_len);
}
/* /*
* A variant of LookupTupleHashEntry for callers that have already computed * A variant of LookupTupleHashEntry for callers that have already computed
* the hash value. * the hash value.
@ -512,31 +477,13 @@ LookupTupleHashEntry_internal(TupleHashTable hashtable, TupleTableSlot *slot,
} }
else else
{ {
MinimalTuple firstTuple;
size_t totalsize; /* including alignment and additionalsize */
/* created new entry */ /* created new entry */
*isnew = true; *isnew = true;
/* zero caller data */ /* zero caller data */
entry->additional = NULL;
MemoryContextSwitchTo(hashtable->tablecxt); MemoryContextSwitchTo(hashtable->tablecxt);
/* Copy the first tuple into the table context */ /* Copy the first tuple into the table context */
firstTuple = ExecCopySlotMinimalTuple(slot); entry->firstTuple = ExecCopySlotMinimalTuple(slot);
/*
* Allocate additional space right after the MinimalTuple of size
* additionalsize. The caller can get a pointer to this data with
* TupleHashEntryGetAdditional(), and store arbitrary data there.
*
* This avoids the need to store an extra pointer or allocate an
* additional chunk, which would waste memory.
*/
totalsize = MAXALIGN(firstTuple->t_len) + hashtable->additionalsize;
firstTuple = repalloc(firstTuple, totalsize);
memset((char *) firstTuple + firstTuple->t_len, 0,
totalsize - firstTuple->t_len);
entry->firstTuple = firstTuple;
} }
} }
else else

View File

@ -1713,7 +1713,7 @@ hash_agg_entry_size(int numTrans, Size tupleWidth, Size transitionSpace)
transitionChunkSize = 0; transitionChunkSize = 0;
return return
TupleHashEntrySize() + sizeof(TupleHashEntryData) +
tupleChunkSize + tupleChunkSize +
pergroupChunkSize + pergroupChunkSize +
transitionChunkSize; transitionChunkSize;
@ -1954,7 +1954,7 @@ hash_agg_update_metrics(AggState *aggstate, bool from_tape, int npartitions)
if (aggstate->hash_ngroups_current > 0) if (aggstate->hash_ngroups_current > 0)
{ {
aggstate->hashentrysize = aggstate->hashentrysize =
TupleHashEntrySize() + sizeof(TupleHashEntryData) +
(hashkey_mem / (double) aggstate->hash_ngroups_current); (hashkey_mem / (double) aggstate->hash_ngroups_current);
} }
} }
@ -2055,7 +2055,11 @@ initialize_hash_entry(AggState *aggstate, TupleHashTable hashtable,
if (aggstate->numtrans == 0) if (aggstate->numtrans == 0)
return; return;
pergroup = (AggStatePerGroup) TupleHashEntryGetAdditional(entry); pergroup = (AggStatePerGroup)
MemoryContextAlloc(hashtable->tablecxt,
sizeof(AggStatePerGroupData) * aggstate->numtrans);
entry->additional = pergroup;
/* /*
* Initialize aggregates for new tuple group, lookup_hash_entries() * Initialize aggregates for new tuple group, lookup_hash_entries()
@ -2119,7 +2123,7 @@ lookup_hash_entries(AggState *aggstate)
{ {
if (isnew) if (isnew)
initialize_hash_entry(aggstate, hashtable, entry); initialize_hash_entry(aggstate, hashtable, entry);
pergroup[setno] = TupleHashEntryGetAdditional(entry); pergroup[setno] = entry->additional;
} }
else else
{ {
@ -2677,7 +2681,7 @@ agg_refill_hash_table(AggState *aggstate)
{ {
if (isnew) if (isnew)
initialize_hash_entry(aggstate, perhash->hashtable, entry); initialize_hash_entry(aggstate, perhash->hashtable, entry);
aggstate->hash_pergroup[batch->setno] = TupleHashEntryGetAdditional(entry); aggstate->hash_pergroup[batch->setno] = entry->additional;
advance_aggregates(aggstate); advance_aggregates(aggstate);
} }
else else
@ -2769,7 +2773,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
ExprContext *econtext; ExprContext *econtext;
AggStatePerAgg peragg; AggStatePerAgg peragg;
AggStatePerGroup pergroup; AggStatePerGroup pergroup;
TupleHashEntry entry; TupleHashEntryData *entry;
TupleTableSlot *firstSlot; TupleTableSlot *firstSlot;
TupleTableSlot *result; TupleTableSlot *result;
AggStatePerHash perhash; AggStatePerHash perhash;
@ -2841,7 +2845,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
* Transform representative tuple back into one with the right * Transform representative tuple back into one with the right
* columns. * columns.
*/ */
ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), hashslot, false); ExecStoreMinimalTuple(entry->firstTuple, hashslot, false);
slot_getallattrs(hashslot); slot_getallattrs(hashslot);
ExecClearTuple(firstSlot); ExecClearTuple(firstSlot);
@ -2857,7 +2861,7 @@ agg_retrieve_hash_table_in_memory(AggState *aggstate)
} }
ExecStoreVirtualTuple(firstSlot); ExecStoreVirtualTuple(firstSlot);
pergroup = (AggStatePerGroup) TupleHashEntryGetAdditional(entry); pergroup = (AggStatePerGroup) entry->additional;
/* /*
* Use the representative input tuple for any references to * Use the representative input tuple for any references to

View File

@ -425,7 +425,6 @@ setop_fill_hash_table(SetOpState *setopstate)
{ {
TupleTableSlot *outerslot; TupleTableSlot *outerslot;
TupleHashEntryData *entry; TupleHashEntryData *entry;
SetOpStatePerGroup pergroup;
bool isnew; bool isnew;
outerslot = ExecProcNode(outerPlan); outerslot = ExecProcNode(outerPlan);
@ -438,16 +437,16 @@ setop_fill_hash_table(SetOpState *setopstate)
outerslot, outerslot,
&isnew, NULL); &isnew, NULL);
pergroup = TupleHashEntryGetAdditional(entry);
/* If new tuple group, initialize counts to zero */ /* If new tuple group, initialize counts to zero */
if (isnew) if (isnew)
{ {
pergroup->numLeft = 0; entry->additional = (SetOpStatePerGroup)
pergroup->numRight = 0; MemoryContextAllocZero(setopstate->hashtable->tablecxt,
sizeof(SetOpStatePerGroupData));
} }
/* Advance the counts */ /* Advance the counts */
pergroup->numLeft++; ((SetOpStatePerGroup) entry->additional)->numLeft++;
/* Must reset expression context after each hashtable lookup */ /* Must reset expression context after each hashtable lookup */
ResetExprContext(econtext); ResetExprContext(econtext);
@ -479,7 +478,7 @@ setop_fill_hash_table(SetOpState *setopstate)
/* Advance the counts if entry is already present */ /* Advance the counts if entry is already present */
if (entry) if (entry)
((SetOpStatePerGroup) TupleHashEntryGetAdditional(entry))->numRight++; ((SetOpStatePerGroup) entry->additional)->numRight++;
/* Must reset expression context after each hashtable lookup */ /* Must reset expression context after each hashtable lookup */
ResetExprContext(econtext); ResetExprContext(econtext);
@ -497,7 +496,7 @@ setop_fill_hash_table(SetOpState *setopstate)
static TupleTableSlot * static TupleTableSlot *
setop_retrieve_hash_table(SetOpState *setopstate) setop_retrieve_hash_table(SetOpState *setopstate)
{ {
TupleHashEntry entry; TupleHashEntryData *entry;
TupleTableSlot *resultTupleSlot; TupleTableSlot *resultTupleSlot;
/* /*
@ -527,12 +526,12 @@ setop_retrieve_hash_table(SetOpState *setopstate)
* See if we should emit any copies of this tuple, and if so return * See if we should emit any copies of this tuple, and if so return
* the first copy. * the first copy.
*/ */
set_output_count(setopstate, (SetOpStatePerGroup) TupleHashEntryGetAdditional(entry)); set_output_count(setopstate, (SetOpStatePerGroup) entry->additional);
if (setopstate->numOutput > 0) if (setopstate->numOutput > 0)
{ {
setopstate->numOutput--; setopstate->numOutput--;
return ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), return ExecStoreMinimalTuple(entry->firstTuple,
resultTupleSlot, resultTupleSlot,
false); false);
} }

View File

@ -753,7 +753,7 @@ findPartialMatch(TupleHashTable hashtable, TupleTableSlot *slot,
{ {
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
ExecStoreMinimalTuple(TupleHashEntryGetTuple(entry), hashtable->tableslot, false); ExecStoreMinimalTuple(entry->firstTuple, hashtable->tableslot, false);
if (!execTuplesUnequal(slot, hashtable->tableslot, if (!execTuplesUnequal(slot, hashtable->tableslot,
numCols, keyColIdx, numCols, keyColIdx,
eqfunctions, eqfunctions,

View File

@ -148,12 +148,9 @@ extern TupleHashEntry LookupTupleHashEntry(TupleHashTable hashtable,
bool *isnew, uint32 *hash); bool *isnew, uint32 *hash);
extern uint32 TupleHashTableHash(TupleHashTable hashtable, extern uint32 TupleHashTableHash(TupleHashTable hashtable,
TupleTableSlot *slot); TupleTableSlot *slot);
extern size_t TupleHashEntrySize(void);
extern TupleHashEntry LookupTupleHashEntryHash(TupleHashTable hashtable, extern TupleHashEntry LookupTupleHashEntryHash(TupleHashTable hashtable,
TupleTableSlot *slot, TupleTableSlot *slot,
bool *isnew, uint32 hash); bool *isnew, uint32 hash);
extern MinimalTuple TupleHashEntryGetTuple(TupleHashEntry entry);
extern void *TupleHashEntryGetAdditional(TupleHashEntry entry);
extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable, extern TupleHashEntry FindTupleHashEntry(TupleHashTable hashtable,
TupleTableSlot *slot, TupleTableSlot *slot,
ExprState *eqcomp, ExprState *eqcomp,

View File

@ -806,10 +806,17 @@ typedef struct ExecAuxRowMark
* point to tab_hash_expr and tab_eq_func respectively. * point to tab_hash_expr and tab_eq_func respectively.
* ---------------------------------------------------------------- * ----------------------------------------------------------------
*/ */
typedef struct TupleHashEntryData TupleHashEntryData;
typedef struct TupleHashEntryData *TupleHashEntry; typedef struct TupleHashEntryData *TupleHashEntry;
typedef struct TupleHashTableData *TupleHashTable; typedef struct TupleHashTableData *TupleHashTable;
typedef struct TupleHashEntryData
{
MinimalTuple firstTuple; /* copy of first tuple in this group */
void *additional; /* user data */
uint32 status; /* hash status */
uint32 hash; /* hash value (cached) */
} TupleHashEntryData;
/* define parameters necessary to generate the tuple hash table interface */ /* define parameters necessary to generate the tuple hash table interface */
#define SH_PREFIX tuplehash #define SH_PREFIX tuplehash
#define SH_ELEMENT_TYPE TupleHashEntryData #define SH_ELEMENT_TYPE TupleHashEntryData
@ -828,7 +835,6 @@ typedef struct TupleHashTableData
Oid *tab_collations; /* collations for hash and comparison */ Oid *tab_collations; /* collations for hash and comparison */
MemoryContext tablecxt; /* memory context containing table */ MemoryContext tablecxt; /* memory context containing table */
MemoryContext tempcxt; /* context for function evaluations */ MemoryContext tempcxt; /* context for function evaluations */
Size additionalsize; /* size of additional data */
TupleTableSlot *tableslot; /* slot for referencing table entries */ TupleTableSlot *tableslot; /* slot for referencing table entries */
/* The following fields are set transiently for each table search: */ /* The following fields are set transiently for each table search: */
TupleTableSlot *inputslot; /* current input tuple's slot */ TupleTableSlot *inputslot; /* current input tuple's slot */