Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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

+71-2
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)