| From: | Tatsuya Kawata <kawatatatsuya0913(at)gmail(dot)com> |
|---|---|
| To: | Postgres hackers <pgsql-hackers(at)lists(dot)postgresql(dot)org> |
| Subject: | Memoize shows only the last execution's stats for parallel workers |
| Date: | 2026-10-12 06:35:30 |
| Message-ID: | CAHza6qeA-4vB355co-2yAxDMRTpEneY0rg9CD2zMLYscYvv2UA@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
I noticed this while reviewing the patch in [1].
When a Gather (or Gather Merge) node is rescanned, a new set of workers
is started, and they write their Memoize stats into the same shared
memory slots as the previous ones. ExecEndMemoize() does this with
memcpy(), so EXPLAIN ANALYZE shows the per-worker Hits / Misses etc.
only for the last execution. Since the "actual rows" and "loops" of the
same worker are accumulated across all executions, the two don't match.
=== Example
CREATE TABLE mz_a (x int);
CREATE TABLE mz_b (y int);
INSERT INTO mz_a SELECT g % 10 FROM generate_series(1, 1000) g;
INSERT INTO mz_b SELECT g FROM generate_series(1, 1000) g;
CREATE INDEX ON mz_b (y);
ANALYZE mz_a, mz_b;
ALTER TABLE mz_a SET (parallel_workers = 2);
SET enable_hashjoin = off;
SET enable_mergejoin = off;
SET enable_material = off;
SET parallel_setup_cost = 0;
SET parallel_tuple_cost = 0;
SET min_parallel_table_scan_size = 0;
SET max_parallel_workers_per_gather = 2;
SET parallel_leader_participation = off;
SET max_parallel_workers = 1; -- so that Worker 0 runs both executions
EXPLAIN (ANALYZE, VERBOSE, COSTS OFF, TIMING OFF, SUMMARY OFF, BUFFERS OFF)
SELECT o.z, (SELECT count(*) + o.z FROM mz_a a JOIN mz_b b ON b.y = a.x)
FROM (VALUES (1), (2)) o(z);
=== Output on master
Hits + Misses (1000) doesn't match the loops (2000), and
Misses (10) doesn't match the loops of the inner Index Only Scan (20):
-> Memoize (actual rows=0.90 loops=2000)
...
Worker 0: actual rows=0.90 loops=2000
Hits: 990 Misses: 10 Evictions: 0 Overflows: 0 Memory Usage:
1kB
-> Index Only Scan using mz_b_y_idx on public.mz_b b (actual
rows=0.90 loops=20)
...
Worker 0: actual rows=0.90 loops=20
=== With the patch
Hits: 1980 Misses: 20 Evictions: 0 Overflows: 0 Memory Usage: 1kB
The attached patch accumulates the stats instead of using memcpy(), as
is already done for Parallel Bitmap Heap Scan (5a1e6df3b84). For Memory
Usage, it keeps the maximum.
Regards,
Tatsuya Kawata
| Attachment | Content-Type | Size |
|---|---|---|
| v1-0001-Accumulate-Memoize-parallel-worker-stats-across-r.patch | application/octet-stream | 1.8 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Rui Zhao | 2026-10-12 06:50:18 | Re: Deprecation warnings on Rocky 10.2 with current dev branch |
| Previous Message | QQ Mail | 2026-10-12 06:35:25 | Re: BUG #19736: `JSON_OBJECT ... ABSENT ON NULL` accepts invalid keys when the value is NULL |