From 3d6e246264b941a811716d106fc9247368769466 Mon Sep 17 00:00:00 2001 From: David Rowley Date: Wed, 14 Oct 2026 22:09:32 +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 1be3bdd55f4..5c262f28bf2 100644 --- a/src/backend/executor/nodeMemoize.c +++ b/src/backend/executor/nodeMemoize.c @@ -1111,7 +1111,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 */