| From: | xiaoyu liu <xliu19163(at)gmail(dot)com> |
|---|---|
| To: | andres(at)anarazel(dot)de, amitlangote09(at)gmail(dot)com, amit(dot)kapila16(at)gmail(dot)com, dgrowleyml(at)gmail(dot)com |
| Cc: | pgsql-hackers(at)postgresql(dot)org |
| Subject: | Re: unnecessary executor overheads around seqscans |
| Date: | 2026-09-07 08:51:30 |
| Message-ID: | CAPPb3yhbokWc0caRiyZOFcW7bA0Sv-WPbbdEehk0UbOaKq6Djw@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
Following up on the earlier discussion:
Andres pointed out that the TupIsNull(slot) check in
ExecScanExtended() is redundant with the result of
table_scan_getnextslot(), but that the compiler cannot infer this
relationship.
Amit proposed adding a pg_assume(), and David confirmed through
objdump that GCC could then remove the redundant check. I noticed
that this change is still not present on current master, so I
prepared the attached patch.
The patch adds the following one-way invariant:
found = sscan->rs_rd->rd_tableam->scan_getnextslot(sscan,
direction,
slot);
pg_assume(!found || !TupIsNull(slot));
return found;
I used the implication form mentioned by Andres instead of:
found == !TupIsNull(slot)
The executor only requires that a successful call leave the slot
non-empty. It does not need to require the slot to be empty whenever
the table AM returns false.
The only in-tree scan_getnextslot implementation is
heap_getnextslot(). It clears the slot before returning false and
calls ExecStoreBufferHeapTuple() before returning true. The latter
clears TTS_FLAG_EMPTY. I also updated the TableAmRoutine callback
comment to document the successful-call contract.
With GCC 12.2.1 on AArch64 at -O2, objdump shows that the
TTS_FLAG_EMPTY load and branch following the table AM callback are
removed. I observed the same optimization with GCC 16. Apple Clang
21 did not eliminate the check in this code shape.
I also ran an in-memory microbenchmark using a single-client count(*)
SeqScan over a 20 million-row, 692 MB heap table, with parallel query
and JIT disabled. Across four alternating baseline/patched pairs of
100 scans each, the paired median improvement was about 0.53%, but
the result remained within measurement noise. This is consistent
with Amit's earlier observation, so I do not claim a measurable
runtime improvement; the demonstrated benefit is the simpler
generated code.
Both regular and assertion-enabled GCC builds passed:
- core regression tests: 243/243
- test_extensible: 1/1
Does this look worthwhile as a small Table AM/executor
code-generation cleanup?
Regards,
Xiaoyu
| Attachment | Content-Type | Size |
|---|---|---|
| v1-0001-tableam-assume-successful-scans-return-nonempty-slots.patch | text/x-patch | 1.7 KB |
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Hayato Kuroda (Fujitsu) | 2026-09-07 08:53:14 | RE: Per-table resync for logical replication subscriptions |
| Previous Message | Hannu Krosing | 2026-09-07 08:47:46 | Re: Direct TOAST v2, faster, smaller and no migration needed |