Skip to content

Commit 2f2b799

Browse files
committed
Optimize prefetch patterns in both heap seqscan and vacuum scans.
Previously, we called PrefetchBuffer [NBlkScanned * seqscan_prefetch_buffers] times in each of those situations, but now only NBlkScanned. In addition, the prefetch mechanism for the vacuum scans is now based on blocks instead of tuples - improving the efficiency.
1 parent 4e4cb63 commit 2f2b799

File tree

2 files changed

+78
-18
lines changed

2 files changed

+78
-18
lines changed

src/backend/access/heap/heapam.c

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -399,19 +399,32 @@ heapgetpage(TableScanDesc sscan, BlockNumber page)
399399
*/
400400
CHECK_FOR_INTERRUPTS();
401401

402-
/* Prefetch next block */
403-
if (enable_seqscan_prefetch)
402+
/* Prefetch up to seqscan_prefetch_buffers blocks ahead */
403+
if (enable_seqscan_prefetch && seqscan_prefetch_buffers > 0)
404404
{
405-
int prefetch_limit = seqscan_prefetch_buffers;
405+
uint32 prefetch_limit = seqscan_prefetch_buffers;
406+
BlockNumber prefetch_start = page;
406407
ParallelBlockTableScanWorker pbscanwork = scan->rs_parallelworkerdata;
408+
407409
if (pbscanwork != NULL && pbscanwork->phsw_chunk_remaining < prefetch_limit)
408410
prefetch_limit = pbscanwork->phsw_chunk_remaining;
409-
if (page + prefetch_limit >= scan->rs_nblocks)
410-
prefetch_limit = scan->rs_nblocks - page - 1;
411411

412-
smgr_reset_prefetch(RelationGetSmgr(scan->rs_base.rs_rd));
412+
/*
413+
* If we've started prefetching buffers, we don't have to prefetch
414+
* all pages in page..page + n, but only page + n; saving N-1 prefetch
415+
* calls.
416+
*/
417+
if (scan->rs_startblock != page)
418+
{
419+
prefetch_start = (page + prefetch_limit - 1) % scan->rs_nblocks;
420+
prefetch_limit = 1;
421+
}
422+
else
423+
prefetch_start = page;
424+
413425
for (int i = 1; i <= prefetch_limit; i++)
414-
PrefetchBuffer(scan->rs_base.rs_rd, MAIN_FORKNUM, page+i);
426+
PrefetchBuffer(scan->rs_base.rs_rd, MAIN_FORKNUM,
427+
(prefetch_start+i) % scan->rs_nblocks);
415428
}
416429

417430
/* read page using selected strategy */

src/backend/access/heap/vacuumlazy.c

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -973,12 +973,27 @@ lazy_scan_heap(LVRelState *vacrel)
973973
*/
974974
visibilitymap_pin(vacrel->rel, blkno, &vmbuffer);
975975

976-
if (enable_seqscan_prefetch)
976+
if (enable_seqscan_prefetch && seqscan_prefetch_buffers > 0)
977977
{
978-
int prefetch_limit = Min(rel_pages - blkno - 1, seqscan_prefetch_buffers);
979-
smgr_reset_prefetch(RelationGetSmgr(vacrel->rel));
980-
for (int i = 1; i <= prefetch_limit; i++)
981-
PrefetchBuffer(vacrel->rel, MAIN_FORKNUM, blkno+i);
978+
/*
979+
* If we're starting the scan, we need to prefetch the first N pages.
980+
* If not, we need to only prefetch page blkno+n.
981+
*/
982+
if (blkno == 0)
983+
{
984+
int prefetch_limit = Min(rel_pages - blkno - 1,
985+
seqscan_prefetch_buffers);
986+
987+
for (int i = 1; i <= prefetch_limit; i++)
988+
PrefetchBuffer(vacrel->rel, MAIN_FORKNUM, blkno+i);
989+
}
990+
else
991+
{
992+
/* No need to prefetch past the end of the relation */
993+
if (blkno + seqscan_prefetch_buffers < rel_pages)
994+
PrefetchBuffer(vacrel->rel, MAIN_FORKNUM,
995+
blkno + seqscan_prefetch_buffers);
996+
}
982997
}
983998

984999
/* Finished preparatory checks. Actually scan the page. */
@@ -2404,7 +2419,8 @@ lazy_vacuum_all_indexes(LVRelState *vacrel)
24042419
static void
24052420
lazy_vacuum_heap_rel(LVRelState *vacrel)
24062421
{
2407-
int index;
2422+
int index,
2423+
pindex;
24082424
BlockNumber vacuumed_pages;
24092425
Buffer vmbuffer = InvalidBuffer;
24102426
LVSavedErrInfo saved_err_info;
@@ -2435,13 +2451,44 @@ lazy_vacuum_heap_rel(LVRelState *vacrel)
24352451
vacuum_delay_point();
24362452

24372453
tblk = ItemPointerGetBlockNumber(&vacrel->dead_items->items[index]);
2438-
if (enable_seqscan_prefetch)
2454+
2455+
if (enable_seqscan_prefetch && seqscan_prefetch_buffers > 0)
24392456
{
2440-
int prefetch_limit = Min(vacrel->dead_items->num_items - index - 1, seqscan_prefetch_buffers);
2441-
smgr_reset_prefetch(RelationGetSmgr(vacrel->rel));
2442-
for (int i = 1; i <= prefetch_limit; i++)
2443-
PrefetchBuffer(vacrel->rel, MAIN_FORKNUM, ItemPointerGetBlockNumber(&vacrel->dead_items->items[index + i]));
2457+
/*
2458+
* If we're just starting out, prefetch N consecutive blocks.
2459+
* If not, only the next 1 block
2460+
*/
2461+
if (index == 0)
2462+
{
2463+
int prefetch_limit = Min(vacrel->dead_items->num_items - 1,
2464+
Min(vacrel->rel_pages,
2465+
seqscan_prefetch_buffers));
2466+
BlockNumber prev_prefetch = 0;
2467+
2468+
while (++pindex < vacrel->dead_items->num_items &&
2469+
prefetch_limit > 0)
2470+
{
2471+
ItemPointer ptr = &vacrel->dead_items->items[pindex];
2472+
if (ItemPointerGetBlockNumber(ptr) != prev_prefetch)
2473+
{
2474+
prev_prefetch = ItemPointerGetBlockNumber(ptr);
2475+
prefetch_limit -= 1;
2476+
PrefetchBuffer(vacrel->rel, MAIN_FORKNUM, prev_prefetch);
2477+
}
2478+
}
2479+
}
2480+
else
2481+
{
2482+
BlockNumber toPrefetch = ItemPointerGetBlockNumber(&vacrel->dead_items->items[pindex]);
2483+
while (pindex < vacrel->dead_items->num_items)
2484+
{
2485+
if (toPrefetch != ItemPointerGetBlockNumber(&vacrel->dead_items->items[pindex]))
2486+
break;
2487+
}
2488+
PrefetchBuffer(vacrel->rel, MAIN_FORKNUM, toPrefetch);
2489+
}
24442490
}
2491+
24452492
vacrel->blkno = tblk;
24462493
buf = ReadBufferExtended(vacrel->rel, MAIN_FORKNUM, tblk, RBM_NORMAL,
24472494
vacrel->bstrategy);

0 commit comments

Comments
 (0)