From 8f83509b3237dacdd7b9d7ba8d51ad750603a038 Mon Sep 17 00:00:00 2001 From: Yuhang Qiu Date: Wed, 26 Aug 2026 11:58:21 +0000 Subject: [PATCH 3/3] explain: Report streaming I/O statistics for sample scans The preceding commit gives sample scans a read stream, but their statistics are not reported by EXPLAIN. Unlike other heap scan streams, a sample scan's stream does not exist when heap_beginscan() returns. Allocate scan instrumentation independently of stream creation, attach it when the sample stream is initialized, and include SampleScan in show_scan_io_usage(). --- src/backend/access/heap/heapam.c | 7 ++++--- src/backend/access/heap/heapam_handler.c | 4 ++++ src/backend/commands/explain.c | 2 ++ src/backend/executor/nodeSamplescan.c | 11 +++++++++-- 4 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index a43d9fb87b1..2e0f09bff78 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -1322,11 +1322,12 @@ heap_beginscan(Relation relation, Snapshot snapshot, } /* enable read stream instrumentation */ - if ((flags & SO_SCAN_INSTRUMENT) && (scan->rs_read_stream != NULL)) + if (flags & SO_SCAN_INSTRUMENT) { scan->rs_base.rs_instrument = palloc0_object(TableScanInstrumentation); - read_stream_enable_stats(scan->rs_read_stream, - &scan->rs_base.rs_instrument->io); + if (scan->rs_read_stream != NULL) + read_stream_enable_stats(scan->rs_read_stream, + &scan->rs_base.rs_instrument->io); } scan->rs_vmbuffer = InvalidBuffer; diff --git a/src/backend/access/heap/heapam_handler.c b/src/backend/access/heap/heapam_handler.c index e804bb0db11..edff0774084 100644 --- a/src/backend/access/heap/heapam_handler.c +++ b/src/backend/access/heap/heapam_handler.c @@ -2222,6 +2222,10 @@ heapam_scan_sample_next_block(TableScanDesc scan, SampleScanState *scanstate) heapam_scan_sample_stream_read_next, scanstate, 0); + + if (hscan->rs_base.rs_instrument) + read_stream_enable_stats(hscan->rs_read_stream, + &hscan->rs_base.rs_instrument->io); } hscan->rs_cbuf = read_stream_next_buffer(hscan->rs_read_stream, NULL); diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index e35e0a649b3..cea6d6f4687 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -4159,6 +4159,8 @@ show_scan_io_usage(ScanState *planstate, ExplainState *es) break; } + case T_SampleScan: + break; default: /* ignore other plans */ return; diff --git a/src/backend/executor/nodeSamplescan.c b/src/backend/executor/nodeSamplescan.c index f3d273e1c5e..9aef0ffb9ed 100644 --- a/src/backend/executor/nodeSamplescan.c +++ b/src/backend/executor/nodeSamplescan.c @@ -19,6 +19,7 @@ #include "access/tsmapi.h" #include "common/pg_prng.h" #include "executor/executor.h" +#include "executor/instrument.h" #include "executor/nodeSamplescan.h" #include "utils/fmgrprotos.h" #include "utils/rel.h" @@ -224,6 +225,7 @@ tablesample_init(SampleScanState *scanstate) Datum datum; bool isnull; uint32 seed; + uint32 flags = SO_NONE; bool allow_sync; int i; ListCell *arg; @@ -292,6 +294,12 @@ tablesample_init(SampleScanState *scanstate) /* Now we can create or reset the HeapScanDesc */ if (scanstate->ss.ss_currentScanDesc == NULL) { + if (ScanRelIsReadOnly(&scanstate->ss)) + flags |= SO_HINT_REL_READ_ONLY; + + if (scanstate->ss.ps.state->es_instrument & INSTRUMENT_IO) + flags |= SO_SCAN_INSTRUMENT; + scanstate->ss.ss_currentScanDesc = table_beginscan_sampling(scanstate->ss.ss_currentRelation, scanstate->ss.ps.state->es_snapshot, @@ -299,8 +307,7 @@ tablesample_init(SampleScanState *scanstate) scanstate->use_bulkread, allow_sync, scanstate->use_pagemode, - ScanRelIsReadOnly(&scanstate->ss) ? - SO_HINT_REL_READ_ONLY : SO_NONE); + flags); } else { -- 2.43.7