Skip to content

Commit 57f5939

Browse files
committed
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
1 parent c85977d commit 57f5939

File tree

1 file changed

+20
-7
lines changed

1 file changed

+20
-7
lines changed

src/backend/executor/nodeMemoize.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -278,11 +278,14 @@ MemoizeHash_equal(struct memoize_hash *tb, const MemoizeKey *key1,
278278
}
279279

280280
/*
281-
* Initialize the hash table to empty.
281+
* Initialize the hash table to empty. The MemoizeState's hashtable field
282+
* must point to NULL.
282283
*/
283284
static void
284285
build_hash_table(MemoizeState *mstate, uint32 size)
285286
{
287+
Assert(mstate->hashtable == NULL);
288+
286289
/* Make a guess at a good size when we're not given a valid size. */
287290
if (size == 0)
288291
size = 1024;
@@ -400,8 +403,10 @@ remove_cache_entry(MemoizeState *mstate, MemoizeEntry *entry)
400403
static void
401404
cache_purge_all(MemoizeState *mstate)
402405
{
403-
uint64 evictions = mstate->hashtable->members;
404-
PlanState *pstate = (PlanState *) mstate;
406+
uint64 evictions = 0;
407+
408+
if (mstate->hashtable != NULL)
409+
evictions = mstate->hashtable->members;
405410

406411
/*
407412
* Likely the most efficient way to remove all items is to just reset the
@@ -410,8 +415,8 @@ cache_purge_all(MemoizeState *mstate)
410415
*/
411416
MemoryContextReset(mstate->tableContext);
412417

413-
/* Make the hash table the same size as the original size */
414-
build_hash_table(mstate, ((Memoize *) pstate->plan)->est_entries);
418+
/* NULLify so we recreate the table on the next call */
419+
mstate->hashtable = NULL;
415420

416421
/* reset the LRU list */
417422
dlist_init(&mstate->lru_list);
@@ -707,6 +712,10 @@ ExecMemoize(PlanState *pstate)
707712

708713
Assert(node->entry == NULL);
709714

715+
/* first call? we'll need a hash table. */
716+
if (unlikely(node->hashtable == NULL))
717+
build_hash_table(node, ((Memoize *) pstate->plan)->est_entries);
718+
710719
/*
711720
* We're only ever in this state for the first call of the
712721
* 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)
10511060
/* Zero the statistics counters */
10521061
memset(&mstate->stats, 0, sizeof(MemoizeInstrumentation));
10531062

1054-
/* Allocate and set up the actual cache */
1055-
build_hash_table(mstate, node->est_entries);
1063+
/*
1064+
* Because it may require a large allocation, we delay building of the
1065+
* hash table until executor run.
1066+
*/
1067+
mstate->hashtable = NULL;
10561068

10571069
return mstate;
10581070
}
@@ -1062,6 +1074,7 @@ ExecEndMemoize(MemoizeState *node)
10621074
{
10631075
#ifdef USE_ASSERT_CHECKING
10641076
/* Validate the memory accounting code is correct in assert builds. */
1077+
if (node->hashtable != NULL)
10651078
{
10661079
int count;
10671080
uint64 mem = 0;

0 commit comments

Comments
 (0)