Re: Batching in executor

From: Denis Smirnov <darthunix(at)gmail(dot)com>
To: Amit Langote <amitlangote09(at)gmail(dot)com>
Cc: Junwang Zhao <zhjwpku(at)gmail(dot)com>, cca5507 <cca5507(at)qq(dot)com>, Daniil Davydov <3danissimo(at)gmail(dot)com>, PostgreSQL-development <pgsql-hackers(at)postgresql(dot)org>, Tomas Vondra <tomas(at)vondra(dot)me>
Subject: Re: Batching in executor
Date: 2026-07-12 17:08:39
Message-ID: 749D4E65-6E1F-4569-AA0D-5C354E138E57@gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hi,

I decided to implement the idea from my previous message as a small heap-only experiment.

The attached patch lets heap_getnextslot() reuse the visible tuple offsets already collected by page mode after the first tuple on a page. It preserves the existing table AM and tuple-at-a-time executor interfaces. Scans without page mode or with scan keys continue to use the existing path.

I benchmarked the patch against master. Negative values mean lower execution time with the patch. Each cell shows the result for 5M and 10M rows, respectively.

My patch relative to master:

all-visible not-all-visible
5M / 10M 5M / 10M
count(*) (no qual) -6.6% / -8.6% -7.0% / -8.6%
count(*) WHERE pass-all -4.6% / -5.7% -8.6% / -9.2%
count(*) WHERE pass-none -11.0% / -10.3% -12.9% / -10.5%

I also repeated the benchmark with Amit's current v8 0001-0003 patch set, using my patch as the baseline. Here negative values mean lower execution time with Amit's patches.

Amit v8 relative to my patch:

all-visible not-all-visible
5M / 10M 5M / 10M
count(*) (no qual) -4.1% / +0.6% -1.3% / +0.2%
count(*) WHERE pass-all -3.0% / -2.0% -2.3% / -1.0%
count(*) WHERE pass-none +0.1% / +1.5% +1.4% / +0.5%

These were release builds with -O2 on an Apple M5 Pro. The tables were prewarmed and fit in shared_buffers. Parallel query, JIT, synchronized sequential scans, and autovacuum were disabled.

For each query I used three warmup executions followed by 31 measured executions. Each value above is calculated from two independent medians using ABBA ordering. For the not-all-visible case, the visibility map was truncated while the tuples themselves remained frozen.

The patch builds successfully and passes make check. I am posting it as a WIP patch for discussion.

Best regards,
Denis Smirnov

Attachment Content-Type Size
v1-0001-Avoid-repeated-heapgettup_pagemode-calls-within-a.patch application/octet-stream 7.8 KB
unknown_filename text/plain 2 bytes

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Alexander Korotkov 2026-07-12 17:17:20 Re: SQL/JSON json_table plan clause
Previous Message Alexander Korotkov 2026-07-12 16:48:21 Re: postgres_fdw could deparse ArrayCoerceExpr