1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-24 10:47:04 +03:00

Delay build of Memoize hash table until executor run

Previously this hash table was built during executor startup.  This
could cause long delays in EXPLAIN (without ANALYZE) when the planner
opts to use a large Memoize hash table.

No backpatch for now due to lack of complaints.

Author: David Rowley
Discussion: https://postgr.es/m/CAApHDvoJktJ5XL=Kjh2a2TFr64R-7eQZV-+jcJrUwoES2GLiWg@mail.gmail.com
This commit is contained in:
David Rowley 2024-01-30 12:37:03 +13:00
parent c85977d8fe
commit 57f59396bb

View File

@ -278,11 +278,14 @@ MemoizeHash_equal(struct memoize_hash *tb, const MemoizeKey *key1,
}
/*
* Initialize the hash table to empty.
* Initialize the hash table to empty. The MemoizeState's hashtable field
* must point to NULL.
*/
static void
build_hash_table(MemoizeState *mstate, uint32 size)
{
Assert(mstate->hashtable == NULL);
/* Make a guess at a good size when we're not given a valid size. */
if (size == 0)
size = 1024;
@ -400,8 +403,10 @@ remove_cache_entry(MemoizeState *mstate, MemoizeEntry *entry)
static void
cache_purge_all(MemoizeState *mstate)
{
uint64 evictions = mstate->hashtable->members;
PlanState *pstate = (PlanState *) mstate;
uint64 evictions = 0;
if (mstate->hashtable != NULL)
evictions = mstate->hashtable->members;
/*
* Likely the most efficient way to remove all items is to just reset the
@ -410,8 +415,8 @@ cache_purge_all(MemoizeState *mstate)
*/
MemoryContextReset(mstate->tableContext);
/* Make the hash table the same size as the original size */
build_hash_table(mstate, ((Memoize *) pstate->plan)->est_entries);
/* NULLify so we recreate the table on the next call */
mstate->hashtable = NULL;
/* reset the LRU list */
dlist_init(&mstate->lru_list);
@ -707,6 +712,10 @@ ExecMemoize(PlanState *pstate)
Assert(node->entry == NULL);
/* first call? we'll need a hash table. */
if (unlikely(node->hashtable == NULL))
build_hash_table(node, ((Memoize *) pstate->plan)->est_entries);
/*
* We're only ever in this state for the first call of the
* scan. Here we have a look to see if we've already seen the
@ -1051,8 +1060,11 @@ ExecInitMemoize(Memoize *node, EState *estate, int eflags)
/* Zero the statistics counters */
memset(&mstate->stats, 0, sizeof(MemoizeInstrumentation));
/* Allocate and set up the actual cache */
build_hash_table(mstate, node->est_entries);
/*
* Because it may require a large allocation, we delay building of the
* hash table until executor run.
*/
mstate->hashtable = NULL;
return mstate;
}
@ -1062,6 +1074,7 @@ ExecEndMemoize(MemoizeState *node)
{
#ifdef USE_ASSERT_CHECKING
/* Validate the memory accounting code is correct in assert builds. */
if (node->hashtable != NULL)
{
int count;
uint64 mem = 0;