| From: | Nazir Bilal Yavuz <byavuz81(at)gmail(dot)com> |
|---|---|
| To: | Yuhang Qiu <iamqyh(at)gmail(dot)com> |
| Cc: | PostgreSQL-development <pgsql-hackers(at)postgresql(dot)org>, Melanie Plageman <melanieplageman(at)gmail(dot)com> |
| Subject: | Re: [PATCH] Use streaming read I/O in sample scans |
| Date: | 2026-08-27 14:31:21 |
| Message-ID: | CAN55FZ3Lik2m9J+EQjzEHSMSBNgAXU5Myt8LFg=D2OQ0i_jUMQ@mail.gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi,
Thank you for working on this!
On Wed, 26 Aug 2026 at 16:46, Yuhang Qiu <iamqyh(at)gmail(dot)com> wrote:
>
> I tested this with a 64 GiB table containing 8,388,608 pages, with one
> row per page. PostgreSQL was restarted before each run to clear shared
> buffers. The main settings were:
> debug_io_direct=data
> io_method=worker
> shared_buffers=128MB
> effective_io_concurrency=16
>
> Results:
> master patch speedup
> SYSTEM(0.1) 829ms 121ms 6.8x
> SYSTEM(1) 7.53s 0.89s 8.4x
> SYSTEM(10) 70.84s 10.62s 6.7x
> SYSTEM_ROWS(100000) 9.05s 0.97s 9.3x
> BERNOULLI(100) LIMIT 100000 1.83s 0.56s 3.3x
>
> With 8 concurrent clients running `SYSTEM(1)`, throughput increased
> from 1.06 TPS to 4.29 TPS.
Nice results!
> Performance was almost unchanged with `effective_io_concurrency=0`.
> With worker I/O and `effective_io_concurrency=1`, the patch was about
> 8% slower. When all data was cached, the regression was about 1% to 2%.
> Queries that stop early, such as `LIMIT` and `SYSTEM_ROWS`, may also
> issue a small number of unused speculative reads.
I think that is expected.
I started reviewing the patches, but it will take some time.
Meanwhile, I think the initscan() strategy changes in 0001 and 0002
fix an independent bug and could be committed separately. Melanie is
CCed since she may know more. Bug:
heap_beginscan() creates a read stream using the current
scan->rs_strategy. On rescan, initscan() recalculates strategy
eligibility and may allocate or free the strategy if the relation
crosses the NBuffers / 4 threshold. However, the reused read stream
retains the original scan->rs_strategy. This can cause the stream to
either keep using no strategy after one is allocated or retain a
dangling pointer after one is freed.
Also, review for the 0001:
+void
+read_stream_set_strategy(ReadStream *stream, BufferAccessStrategy strategy)
+{
+ Assert(stream->pinned_buffers == 0);
+ Assert(stream->ios_in_progress == 0);
+ Assert(stream->pending_read_nblocks == 0);
+
+ stream->max_pinned_buffers = Min(stream->queue_size - 1,
+ GetAccessStrategyPinLimit(strategy));
stream->max_pinned_buffers might be 0 after this, it should be at
least 1 to proceed.
Another thing is, GetAccessStrategyPinLimit() could return higher
number than current stream->max_pinned_buffers, it would make sense to
re-create stream on some of this cases because it might be faster. I
am not sure how to calculate that, though.
+
+ if (stream->stats)
+ stream->stats->distance_capacity = stream->max_pinned_buffers;
You change distance_capacity but we are still in the same scan. I
think distance_capacity should be highest stream->max_pinned_buffers,
which is the first one as it might only decrease. So, no need to
change it.
--
Regards,
Nazir Bilal Yavuz
Microsoft
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Nikita Malakhov | 2026-08-27 14:36:27 | Re: [(known) BUG] DELETE/UPDATE more than one row in partitioned foreign table |
| Previous Message | Osama Abdul Qader | 2026-08-27 14:23:39 | Re: REPACK (ANALYZE) within transaction block segfaults |