diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 9845b0b..410d487 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -58,10 +58,18 @@ /* Data structure for Algorithm S from Knuth 3.4.2 */ typedef struct { + Relation rel; + ForkNumber forknum; + BlockNumber N; /* number of blocks, known in advance */ int n; /* desired sample size */ BlockNumber t; /* current block number */ int m; /* blocks selected so far */ + + int prefetch_target; + int start; + int end; + BlockNumber *prefetched; } BlockSamplerData; typedef BlockSamplerData *BlockSampler; @@ -87,10 +95,11 @@ static BufferAccessStrategy vac_strategy; static void do_analyze_rel(Relation onerel, VacuumStmt *vacstmt, AcquireSampleRowsFunc acquirefunc, BlockNumber relpages, bool inh, int elevel); -static void BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, +static void BlockSampler_Init(BlockSampler bs, Relation rel, ForkNumber forknum, BlockNumber nblocks, int samplesize); static bool BlockSampler_HasMore(BlockSampler bs); static BlockNumber BlockSampler_Next(BlockSampler bs); +static BlockNumber BlockSampler_Next_internal(BlockSampler bs); static void compute_index_stats(Relation onerel, double totalrows, AnlIndexData *indexdata, int nindexes, HeapTuple *rows, int numrows, @@ -954,8 +963,12 @@ examine_attribute(Relation onerel, int attnum, Node *index_expr) * algorithm. */ static void -BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, int samplesize) +BlockSampler_Init(BlockSampler bs, Relation rel, ForkNumber forknum, + BlockNumber nblocks, int samplesize) { + bs->rel = rel; + bs->forknum = forknum; + bs->N = nblocks; /* measured table size */ /* @@ -965,17 +978,61 @@ BlockSampler_Init(BlockSampler bs, BlockNumber nblocks, int samplesize) bs->n = samplesize; bs->t = 0; /* blocks scanned so far */ bs->m = 0; /* blocks selected so far */ + + bs->prefetch_target = target_prefetch_pages; + if (target_prefetch_pages > 0) + bs->prefetched = palloc((bs->prefetch_target + 1) * sizeof(BlockNumber)); + else + bs->prefetched = NULL; + bs->start = bs->end = 0; } static bool BlockSampler_HasMore(BlockSampler bs) { + if (bs->end != bs->start) + return true; return (bs->t < bs->N) && (bs->m < bs->n); } +static void +BlockSampler_Prefetch(BlockSampler bs) +{ + int next; + + next = (bs->end + 1) % (bs->prefetch_target + 1); + while (next != bs->start && (bs->t < bs->N) && (bs->m < bs->n)) + { + BlockNumber blk = BlockSampler_Next_internal(bs); + + PrefetchBuffer(bs->rel, bs->forknum, blk); + + bs->prefetched[bs->end] = blk; + bs->end = next; + next = (bs->end + 1) % (bs->prefetch_target + 1); + } +} + static BlockNumber BlockSampler_Next(BlockSampler bs) { + BlockNumber result; + + if (bs->prefetch_target == 0) + return BlockSampler_Next_internal(bs); + + BlockSampler_Prefetch(bs); + + Assert(bs->end != bs->start); + + result = bs->prefetched[bs->start]; + bs->start = (bs->start + 1) % (bs->prefetch_target + 1); + return result; +} + +static BlockNumber +BlockSampler_Next_internal(BlockSampler bs) +{ BlockNumber K = bs->N - bs->t; /* remaining blocks */ int k = bs->n - bs->m; /* blocks still to sample */ double p; /* probability to skip block */ @@ -1084,7 +1141,7 @@ acquire_sample_rows(Relation onerel, int elevel, OldestXmin = GetOldestXmin(onerel->rd_rel->relisshared, true); /* Prepare for sampling block numbers */ - BlockSampler_Init(&bs, totalblocks, targrows); + BlockSampler_Init(&bs, onerel, MAIN_FORKNUM, totalblocks, targrows); /* Prepare for sampling rows */ rstate = anl_init_selection_state(targrows);