Skip to content

Commit c6fc50c

Browse files
committed
Use pre-fetching for ANALYZE
When we have posix_fadvise() available, we can improve the performance of an ANALYZE by quite a bit by using it to inform the kernel of the blocks that we're going to be asking for. Similar to bitmap index scans, the number of buffers pre-fetched is based off of the maintenance_io_concurrency setting (for the particular tablespace or, if not set, globally, via get_tablespace_maintenance_io_concurrency()). Reviewed-By: Heikki Linnakangas, Tomas Vondra Discussion: https://www.postgresql.org/message-id/VI1PR0701MB69603A433348EDCF783C6ECBF6EF0%40VI1PR0701MB6960.eurprd07.prod.outlook.com
1 parent 94d13d4 commit c6fc50c

File tree

1 file changed

+71
-2
lines changed

1 file changed

+71
-2
lines changed

src/backend/commands/analyze.c

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
#include "utils/pg_rusage.h"
6464
#include "utils/sampling.h"
6565
#include "utils/sortsupport.h"
66+
#include "utils/spccache.h"
6667
#include "utils/syscache.h"
6768
#include "utils/timestamp.h"
6869

@@ -1127,6 +1128,7 @@ acquire_sample_rows(Relation onerel, int elevel,
11271128
double liverows = 0; /* # live rows seen */
11281129
double deadrows = 0; /* # dead rows seen */
11291130
double rowstoskip = -1; /* -1 means not set yet */
1131+
long randseed; /* Seed for block sampler(s) */
11301132
BlockNumber totalblocks;
11311133
TransactionId OldestXmin;
11321134
BlockSamplerData bs;
@@ -1135,6 +1137,10 @@ acquire_sample_rows(Relation onerel, int elevel,
11351137
TableScanDesc scan;
11361138
BlockNumber nblocks;
11371139
BlockNumber blksdone = 0;
1140+
#ifdef USE_PREFETCH
1141+
int prefetch_maximum = 0; /* blocks to prefetch if enabled */
1142+
BlockSamplerData prefetch_bs;
1143+
#endif
11381144

11391145
Assert(targrows > 0);
11401146

@@ -1144,7 +1150,15 @@ acquire_sample_rows(Relation onerel, int elevel,
11441150
OldestXmin = GetOldestNonRemovableTransactionId(onerel);
11451151

11461152
/* Prepare for sampling block numbers */
1147-
nblocks = BlockSampler_Init(&bs, totalblocks, targrows, random());
1153+
randseed = random();
1154+
nblocks = BlockSampler_Init(&bs, totalblocks, targrows, randseed);
1155+
1156+
#ifdef USE_PREFETCH
1157+
prefetch_maximum = get_tablespace_io_concurrency(onerel->rd_rel->reltablespace);
1158+
/* Create another BlockSampler, using the same seed, for prefetching */
1159+
if (prefetch_maximum)
1160+
(void) BlockSampler_Init(&prefetch_bs, totalblocks, targrows, randseed);
1161+
#endif
11481162

11491163
/* Report sampling block numbers */
11501164
pgstat_progress_update_param(PROGRESS_ANALYZE_BLOCKS_TOTAL,
@@ -1156,14 +1170,69 @@ acquire_sample_rows(Relation onerel, int elevel,
11561170
scan = table_beginscan_analyze(onerel);
11571171
slot = table_slot_create(onerel, NULL);
11581172

1173+
#ifdef USE_PREFETCH
1174+
1175+
/*
1176+
* If we are doing prefetching, then go ahead and tell the kernel about
1177+
* the first set of pages we are going to want. This also moves our
1178+
* iterator out ahead of the main one being used, where we will keep it so
1179+
* that we're always pre-fetching out prefetch_maximum number of blocks
1180+
* ahead.
1181+
*/
1182+
if (prefetch_maximum)
1183+
{
1184+
for (int i = 0; i < prefetch_maximum; i++)
1185+
{
1186+
BlockNumber prefetch_block;
1187+
1188+
if (!BlockSampler_HasMore(&prefetch_bs))
1189+
break;
1190+
1191+
prefetch_block = BlockSampler_Next(&prefetch_bs);
1192+
PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, prefetch_block);
1193+
}
1194+
}
1195+
#endif
1196+
11591197
/* Outer loop over blocks to sample */
11601198
while (BlockSampler_HasMore(&bs))
11611199
{
1200+
bool block_accepted;
11621201
BlockNumber targblock = BlockSampler_Next(&bs);
1202+
#ifdef USE_PREFETCH
1203+
BlockNumber prefetch_targblock = InvalidBlockNumber;
1204+
1205+
/*
1206+
* Make sure that every time the main BlockSampler is moved forward
1207+
* that our prefetch BlockSampler also gets moved forward, so that we
1208+
* always stay out ahead.
1209+
*/
1210+
if (prefetch_maximum && BlockSampler_HasMore(&prefetch_bs))
1211+
prefetch_targblock = BlockSampler_Next(&prefetch_bs);
1212+
#endif
11631213

11641214
vacuum_delay_point();
11651215

1166-
if (!table_scan_analyze_next_block(scan, targblock, vac_strategy))
1216+
block_accepted = table_scan_analyze_next_block(scan, targblock, vac_strategy);
1217+
1218+
#ifdef USE_PREFETCH
1219+
1220+
/*
1221+
* When pre-fetching, after we get a block, tell the kernel about the
1222+
* next one we will want, if there's any left.
1223+
*
1224+
* We want to do this even if the table_scan_analyze_next_block() call
1225+
* above decides against analyzing the block it picked.
1226+
*/
1227+
if (prefetch_maximum && prefetch_targblock != InvalidBlockNumber)
1228+
PrefetchBuffer(scan->rs_rd, MAIN_FORKNUM, prefetch_targblock);
1229+
#endif
1230+
1231+
/*
1232+
* Don't analyze if table_scan_analyze_next_block() indicated this
1233+
* block is unsuitable for analyzing.
1234+
*/
1235+
if (!block_accepted)
11671236
continue;
11681237

11691238
while (table_scan_analyze_next_tuple(scan, OldestXmin, &liverows, &deadrows, slot))

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy