From 8b9ffcb11061c47c1071d8e5e4825e76fc333afe Mon Sep 17 00:00:00 2001 From: David Rowley Date: Wed, 14 Oct 2026 22:06:30 +1300 Subject: [PATCH] Accumulate Memoize parallel worker stats across rescans When a Gather or Gather Merge node is rescanned, it starts a new set of workers, which write their Memoize stats into the same shared memory slots as the previous worker. ExecEndMemoize() used memcpy() for this, so EXPLAIN ANALYZE showed only the stats for the final scan. Here we adjust ExecEndMemoize() to accumulate the counters so that we gather up the totals over all rescans. Author: Tatsuya Kawata Reviewed-by: David Rowley Discussion: https://postgr.es/m/CAHza6qeA-4vB355co-2yAxDMRTpEneY0rg9CD2zMLYscYvv2UA@mail.gmail.com Backpatch-through: 14 --- src/backend/executor/nodeMemoize.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/backend/executor/nodeMemoize.c b/src/backend/executor/nodeMemoize.c index a51dab1803f..023468e056c 100644 --- a/src/backend/executor/nodeMemoize.c +++ b/src/backend/executor/nodeMemoize.c @@ -1162,7 +1162,16 @@ ExecEndMemoize(MemoizeState *node) Assert(ParallelWorkerNumber < node->shared_info->num_workers); si = &node->shared_info->sinstrument[ParallelWorkerNumber]; - memcpy(si, &node->stats, sizeof(MemoizeInstrumentation)); + + /* + * Gather and GatherMerge spin up new workers on rescan, so add these + * counters to accumulate the values over all scans. + */ + si->cache_hits += node->stats.cache_hits; + si->cache_misses += node->stats.cache_misses; + si->cache_evictions += node->stats.cache_evictions; + si->cache_overflows += node->stats.cache_overflows; + si->mem_peak = Max(si->mem_peak, node->stats.mem_peak); } /* Remove the cache context */