It seems that my mailing client set wrong MIME types for attached patch and it
was filtered by the web archive. So I attach the patch again for the web
archive.
diff --git a/contrib/file_fdw/file_fdw.c b/contrib/file_fdw/file_fdw.c
index 9863e32748..3cdb839489 100644
--- a/contrib/file_fdw/file_fdw.c
+++ b/contrib/file_fdw/file_fdw.c
@@ -159,6 +159,7 @@ static void estimate_costs(PlannerInfo *root, RelOptInfo
*baserel,
FileFdwPlanState
*fdw_private,
Cost *startup_cost, Cost
*total_cost);
static int file_acquire_sample_rows(Relation onerel, int elevel,
+ int
natts, VacAttrStats **stats,
HeapTuple *rows, int targrows,
double
*totalrows, double *totaldeadrows);
@@ -1093,6 +1094,7 @@ estimate_costs(PlannerInfo *root, RelOptInfo *baserel,
*/
static int
file_acquire_sample_rows(Relation onerel, int elevel,
+ int natts, VacAttrStats
**stats,
HeapTuple *rows, int targrows,
double *totalrows, double
*totaldeadrows)
{
diff --git a/contrib/postgres_fdw/postgres_fdw.c
b/contrib/postgres_fdw/postgres_fdw.c
index b6c72e1d1e..471970601a 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -466,6 +466,7 @@ static void process_query_params(ExprContext *econtext,
List
*param_exprs,
const char
**param_values);
static int postgresAcquireSampleRowsFunc(Relation relation, int elevel,
+
int natts, VacAttrStats **stats,
HeapTuple *rows, int targrows,
double *totalrows,
double *totaldeadrows);
@@ -4483,6 +4484,7 @@ postgresAnalyzeForeignTable(Relation relation,
*/
static int
postgresAcquireSampleRowsFunc(Relation relation, int elevel,
+ int natts,
VacAttrStats **stats,
HeapTuple *rows, int
targrows,
double *totalrows,
double *totaldeadrows)
diff --git a/src/backend/access/heap/heapam_handler.c
b/src/backend/access/heap/heapam_handler.c
index 3eea215b85..b2f31626b8 100644
--- a/src/backend/access/heap/heapam_handler.c
+++ b/src/backend/access/heap/heapam_handler.c
@@ -33,6 +33,7 @@
#include "catalog/storage.h"
#include "catalog/storage_xlog.h"
#include "commands/progress.h"
+#include "commands/vacuum.h"
#include "executor/executor.h"
#include "miscadmin.h"
#include "pgstat.h"
@@ -44,6 +45,7 @@
#include "storage/smgr.h"
#include "utils/builtins.h"
#include "utils/rel.h"
+#include "utils/sampling.h"
static void reform_and_rewrite_tuple(HeapTuple tuple,
Relation OldHeap, Relation NewHeap,
@@ -1154,6 +1156,151 @@ heapam_scan_analyze_next_tuple(TableScanDesc scan,
TransactionId OldestXmin,
return false;
}
+/*
+ * As of May 2004 we use a new two-stage method: Stage one selects up
+ * to targrows random blocks (or all blocks, if there aren't so many).
+ * Stage two scans these blocks and uses the Vitter algorithm to create
+ * a random sample of targrows rows (or less, if there are less in the
+ * sample of blocks). The two stages are executed simultaneously: each
+ * block is processed as soon as stage one returns its number and while
+ * the rows are read stage two controls which ones are to be inserted
+ * into the sample.
+ *
+ * Although every row has an equal chance of ending up in the final
+ * sample, this sampling method is not perfect: not every possible
+ * sample has an equal chance of being selected. For large relations
+ * the number of different blocks represented by the sample tends to be
+ * too small. We can live with that for now. Improvements are welcome.
+ *
+ * An important property of this sampling method is that because we do
+ * look at a statistically unbiased set of blocks, we should get
+ * unbiased estimates of the average numbers of live and dead rows per
+ * block. The previous sampling method put too much credence in the row
+ * density near the start of the table.
+ */
+static int
+heapam_acquire_sample_rows(TableScanDesc scan, int elevel,
+ int natts, VacAttrStats
**stats,
+ BufferAccessStrategy
bstrategy,
+ HeapTuple *rows, int
targrows,
+ double *totalrows, double
*totaldeadrows)
+{
+ int numrows = 0; /* # rows now in reservoir */
+ double samplerows = 0; /* total # rows collected */
+ double liverows = 0; /* # live rows seen */
+ double deadrows = 0; /* # dead rows seen */
+ double rowstoskip = -1; /* -1 means not set yet */
+ BlockNumber totalblocks;
+ TransactionId OldestXmin;
+ BlockSamplerData bs;
+ ReservoirStateData rstate;
+ TupleTableSlot *slot;
+ BlockNumber nblocks;
+
+ totalblocks = RelationGetNumberOfBlocks(scan->rs_rd);
+
+ /* Need a cutoff xmin for HeapTupleSatisfiesVacuum */
+ OldestXmin = GetOldestNonRemovableTransactionId(scan->rs_rd);
+
+ /* Prepare for sampling block numbers */
+ nblocks = BlockSampler_Init(&bs, totalblocks, targrows, random());
+
+ /* Prepare for sampling rows */
+ reservoir_init_selection_state(&rstate, targrows);
+
+ slot = table_slot_create(scan->rs_rd, NULL);
+
+ /* Outer loop over blocks to sample */
+ while (BlockSampler_HasMore(&bs))
+ {
+ BlockNumber targblock = BlockSampler_Next(&bs);
+
+ vacuum_delay_point();
+
+ if (!heapam_scan_analyze_next_block(scan, targblock, bstrategy))
+ continue;
+
+ while (heapam_scan_analyze_next_tuple(scan, OldestXmin,
&liverows, &deadrows, slot))
+ {
+ /*
+ * The first targrows sample rows are simply copied
into the
+ * reservoir. Then we start replacing tuples in the
sample until
+ * we reach the end of the relation. This algorithm is
from Jeff
+ * Vitter's paper (see full citation in
utils/misc/sampling.c). It
+ * works by repeatedly computing the number of tuples
to skip
+ * before selecting a tuple, which replaces a randomly
chosen
+ * element of the reservoir (current set of tuples).
At all times
+ * the reservoir is a true random sample of the tuples
we've
+ * passed over so far, so when we fall off the end of
the relation
+ * we're done.
+ */
+ if (numrows < targrows)
+ rows[numrows++] = ExecCopySlotHeapTuple(slot);
+ else
+ {
+ /*
+ * t in Vitter's paper is the number of records
already
+ * processed. If we need to compute a new S
value, we must
+ * use the not-yet-incremented value of
samplerows as t.
+ */
+ if (rowstoskip < 0)
+ rowstoskip =
reservoir_get_next_S(&rstate, samplerows, targrows);
+
+ if (rowstoskip <= 0)
+ {
+ /*
+ * Found a suitable tuple, so save it,
replacing one old
+ * tuple at random
+ */
+ int k = (int)
(targrows * sampler_random_fract(rstate.randstate));
+
+ Assert(k >= 0 && k < targrows);
+ heap_freetuple(rows[k]);
+ rows[k] = ExecCopySlotHeapTuple(slot);
+ }
+
+ rowstoskip -= 1;
+ }
+
+ samplerows += 1;
+ }
+ }
+
+ ExecDropSingleTupleTableSlot(slot);
+
+ /*
+ * Estimate total numbers of live and dead rows in relation,
extrapolating
+ * on the assumption that the average tuple density in pages we didn't
+ * scan is the same as in the pages we did scan. Since what we scanned
is
+ * a random sample of the pages in the relation, this should be a good
+ * assumption.
+ */
+ if (bs.m > 0)
+ {
+ *totalrows = floor((liverows / bs.m) * totalblocks + 0.5);
+ *totaldeadrows = floor((deadrows / bs.m) * totalblocks + 0.5);
+ }
+ else
+ {
+ *totalrows = 0.0;
+ *totaldeadrows = 0.0;
+ }
+
+ /*
+ * Emit some interesting relation info
+ */
+ ereport(elevel,
+ (errmsg("\"%s\": scanned %d of %u pages, "
+ "containing %.0f live rows and %.0f
dead rows; "
+ "%d rows in sample, %.0f estimated
total rows",
+ RelationGetRelationName(scan->rs_rd),
+ bs.m, totalblocks,
+ liverows, deadrows,
+ numrows, *totalrows)));
+
+ return numrows;
+}
+
static double
heapam_index_build_range_scan(Relation heapRelation,
Relation
indexRelation,
@@ -1657,13 +1804,13 @@ heapam_index_build_range_scan(Relation heapRelation,
offnum = ItemPointerGetOffsetNumber(&heapTuple->t_self);
/*
- * If a HOT tuple points to a root that we don't know
- * about, obtain root items afresh. If that still
fails,
- * report it as corruption.
+ * If a HOT tuple points to a root that we don't know
about,
+ * obtain root items afresh. If that still fails,
report it as
+ * corruption.
*/
if (root_offsets[offnum - 1] == InvalidOffsetNumber)
{
- Page page = BufferGetPage(hscan->rs_cbuf);
+ Page page =
BufferGetPage(hscan->rs_cbuf);
LockBuffer(hscan->rs_cbuf, BUFFER_LOCK_SHARE);
heap_get_root_tuples(page, root_offsets);
@@ -2569,8 +2716,7 @@ static const TableAmRoutine heapam_methods = {
.relation_copy_data = heapam_relation_copy_data,
.relation_copy_for_cluster = heapam_relation_copy_for_cluster,
.relation_vacuum = heap_vacuum_rel,
- .scan_analyze_next_block = heapam_scan_analyze_next_block,
- .scan_analyze_next_tuple = heapam_scan_analyze_next_tuple,
+ .acquire_sample_rows = heapam_acquire_sample_rows,
.index_build_range_scan = heapam_index_build_range_scan,
.index_validate_scan = heapam_index_validate_scan,
diff --git a/src/backend/access/table/tableamapi.c
b/src/backend/access/table/tableamapi.c
index 58de0743ba..0a981e20e4 100644
--- a/src/backend/access/table/tableamapi.c
+++ b/src/backend/access/table/tableamapi.c
@@ -87,8 +87,7 @@ GetTableAmRoutine(Oid amhandler)
Assert(routine->relation_copy_data != NULL);
Assert(routine->relation_copy_for_cluster != NULL);
Assert(routine->relation_vacuum != NULL);
- Assert(routine->scan_analyze_next_block != NULL);
- Assert(routine->scan_analyze_next_tuple != NULL);
+ Assert(routine->acquire_sample_rows != NULL);
Assert(routine->index_build_range_scan != NULL);
Assert(routine->index_validate_scan != NULL);
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 8af12b5c6b..e6476d7047 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -37,7 +37,6 @@
#include "commands/dbcommands.h"
#include "commands/progress.h"
#include "commands/tablecmds.h"
-#include "commands/vacuum.h"
#include "executor/executor.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
@@ -61,7 +60,6 @@
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/pg_rusage.h"
-#include "utils/sampling.h"
#include "utils/sortsupport.h"
#include "utils/syscache.h"
#include "utils/timestamp.h"
@@ -96,10 +94,12 @@ static void compute_index_stats(Relation onerel, double
totalrows,
static VacAttrStats *examine_attribute(Relation onerel, int attnum,
Node
*index_expr);
static int acquire_sample_rows(Relation onerel, int elevel,
+ int natts,
VacAttrStats **stats,
HeapTuple
*rows, int targrows,
double
*totalrows, double *totaldeadrows);
static int compare_rows(const void *a, const void *b);
static int acquire_inherited_sample_rows(Relation onerel, int elevel,
+
int natts, VacAttrStats **stats,
HeapTuple *rows, int targrows,
double *totalrows, double *totaldeadrows);
static void update_attstats(Oid relid, bool inh,
@@ -505,10 +505,12 @@ do_analyze_rel(Relation onerel, VacuumParams *params,
PROGRESS_ANALYZE_PHASE_ACQUIRE_SAMPLE_ROWS);
if (inh)
numrows = acquire_inherited_sample_rows(onerel, elevel,
+
attr_cnt, vacattrstats,
rows, targrows,
&totalrows, &totaldeadrows);
else
numrows = (*acquirefunc) (onerel, elevel,
+ attr_cnt,
vacattrstats,
rows,
targrows,
&totalrows,
&totaldeadrows);
@@ -999,127 +1001,26 @@ examine_attribute(Relation onerel, int attnum, Node
*index_expr)
*
* The returned list of tuples is in order by physical position in the table.
* (We will rely on this later to derive correlation estimates.)
- *
- * As of May 2004 we use a new two-stage method: Stage one selects up
- * to targrows random blocks (or all blocks, if there aren't so many).
- * Stage two scans these blocks and uses the Vitter algorithm to create
- * a random sample of targrows rows (or less, if there are less in the
- * sample of blocks). The two stages are executed simultaneously: each
- * block is processed as soon as stage one returns its number and while
- * the rows are read stage two controls which ones are to be inserted
- * into the sample.
- *
- * Although every row has an equal chance of ending up in the final
- * sample, this sampling method is not perfect: not every possible
- * sample has an equal chance of being selected. For large relations
- * the number of different blocks represented by the sample tends to be
- * too small. We can live with that for now. Improvements are welcome.
- *
- * An important property of this sampling method is that because we do
- * look at a statistically unbiased set of blocks, we should get
- * unbiased estimates of the average numbers of live and dead rows per
- * block. The previous sampling method put too much credence in the row
- * density near the start of the table.
*/
static int
acquire_sample_rows(Relation onerel, int elevel,
+ int natts, VacAttrStats **stats,
HeapTuple *rows, int targrows,
double *totalrows, double
*totaldeadrows)
{
int numrows = 0; /* # rows now in reservoir */
- double samplerows = 0; /* total # rows collected */
- double liverows = 0; /* # live rows seen */
- double deadrows = 0; /* # dead rows seen */
- double rowstoskip = -1; /* -1 means not set yet */
- BlockNumber totalblocks;
- TransactionId OldestXmin;
- BlockSamplerData bs;
- ReservoirStateData rstate;
- TupleTableSlot *slot;
TableScanDesc scan;
- BlockNumber nblocks;
- BlockNumber blksdone = 0;
Assert(targrows > 0);
- totalblocks = RelationGetNumberOfBlocks(onerel);
-
- /* Need a cutoff xmin for HeapTupleSatisfiesVacuum */
- OldestXmin = GetOldestNonRemovableTransactionId(onerel);
-
- /* Prepare for sampling block numbers */
- nblocks = BlockSampler_Init(&bs, totalblocks, targrows, random());
-
- /* Report sampling block numbers */
- pgstat_progress_update_param(PROGRESS_ANALYZE_BLOCKS_TOTAL,
- nblocks);
-
- /* Prepare for sampling rows */
- reservoir_init_selection_state(&rstate, targrows);
-
scan = table_beginscan_analyze(onerel);
- slot = table_slot_create(onerel, NULL);
- /* Outer loop over blocks to sample */
- while (BlockSampler_HasMore(&bs))
- {
- BlockNumber targblock = BlockSampler_Next(&bs);
+ numrows = table_acquire_sample_rows(scan, elevel,
+
natts, stats,
+
vac_strategy, rows,
+
targrows, totalrows,
+
totaldeadrows);
- vacuum_delay_point();
-
- if (!table_scan_analyze_next_block(scan, targblock,
vac_strategy))
- continue;
-
- while (table_scan_analyze_next_tuple(scan, OldestXmin,
&liverows, &deadrows, slot))
- {
- /*
- * The first targrows sample rows are simply copied
into the
- * reservoir. Then we start replacing tuples in the
sample until
- * we reach the end of the relation. This algorithm is
from Jeff
- * Vitter's paper (see full citation in
utils/misc/sampling.c). It
- * works by repeatedly computing the number of tuples
to skip
- * before selecting a tuple, which replaces a randomly
chosen
- * element of the reservoir (current set of tuples).
At all times
- * the reservoir is a true random sample of the tuples
we've
- * passed over so far, so when we fall off the end of
the relation
- * we're done.
- */
- if (numrows < targrows)
- rows[numrows++] = ExecCopySlotHeapTuple(slot);
- else
- {
- /*
- * t in Vitter's paper is the number of records
already
- * processed. If we need to compute a new S
value, we must
- * use the not-yet-incremented value of
samplerows as t.
- */
- if (rowstoskip < 0)
- rowstoskip =
reservoir_get_next_S(&rstate, samplerows, targrows);
-
- if (rowstoskip <= 0)
- {
- /*
- * Found a suitable tuple, so save it,
replacing one old
- * tuple at random
- */
- int k = (int)
(targrows * sampler_random_fract(rstate.randstate));
-
- Assert(k >= 0 && k < targrows);
- heap_freetuple(rows[k]);
- rows[k] = ExecCopySlotHeapTuple(slot);
- }
-
- rowstoskip -= 1;
- }
-
- samplerows += 1;
- }
-
- pgstat_progress_update_param(PROGRESS_ANALYZE_BLOCKS_DONE,
-
++blksdone);
- }
-
- ExecDropSingleTupleTableSlot(slot);
table_endscan(scan);
/*
@@ -1133,36 +1034,6 @@ acquire_sample_rows(Relation onerel, int elevel,
if (numrows == targrows)
qsort((void *) rows, numrows, sizeof(HeapTuple), compare_rows);
- /*
- * Estimate total numbers of live and dead rows in relation,
extrapolating
- * on the assumption that the average tuple density in pages we didn't
- * scan is the same as in the pages we did scan. Since what we scanned
is
- * a random sample of the pages in the relation, this should be a good
- * assumption.
- */
- if (bs.m > 0)
- {
- *totalrows = floor((liverows / bs.m) * totalblocks + 0.5);
- *totaldeadrows = floor((deadrows / bs.m) * totalblocks + 0.5);
- }
- else
- {
- *totalrows = 0.0;
- *totaldeadrows = 0.0;
- }
-
- /*
- * Emit some interesting relation info
- */
- ereport(elevel,
- (errmsg("\"%s\": scanned %d of %u pages, "
- "containing %.0f live rows and %.0f
dead rows; "
- "%d rows in sample, %.0f estimated
total rows",
- RelationGetRelationName(onerel),
- bs.m, totalblocks,
- liverows, deadrows,
- numrows, *totalrows)));
-
return numrows;
}
@@ -1201,6 +1072,7 @@ compare_rows(const void *a, const void *b)
*/
static int
acquire_inherited_sample_rows(Relation onerel, int elevel,
+ int natts,
VacAttrStats **stats,
HeapTuple *rows, int
targrows,
double *totalrows,
double *totaldeadrows)
{
@@ -1374,6 +1246,7 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
/* Fetch a random sample of the child's rows */
childrows = (*acquirefunc) (childrel, elevel,
+
natts, stats,
rows + numrows, childtargrows,
&trows, &tdrows);
diff --git a/src/include/access/tableam.h b/src/include/access/tableam.h
index 387eb34a61..f9359e27ed 100644
--- a/src/include/access/tableam.h
+++ b/src/include/access/tableam.h
@@ -20,6 +20,7 @@
#include "access/relscan.h"
#include "access/sdir.h"
#include "access/xact.h"
+#include "commands/vacuum.h"
#include "utils/guc.h"
#include "utils/rel.h"
#include "utils/snapshot.h"
@@ -502,39 +503,18 @@ typedef struct TableAmRoutine
BufferAccessStrategy bstrategy);
/*
- * Prepare to analyze block `blockno` of `scan`. The scan has been
started
- * with table_beginscan_analyze(). See also
- * table_scan_analyze_next_block().
- *
- * The callback may acquire resources like locks that are held until
- * table_scan_analyze_next_tuple() returns false. It e.g. can make sense
- * to hold a lock until all tuples on a block have been analyzed by
- * scan_analyze_next_tuple.
- *
- * The callback can return false if the block is not suitable for
- * sampling, e.g. because it's a metapage that could never contain
tuples.
- *
- * XXX: This obviously is primarily suited for block-based AMs. It's not
- * clear what a good interface for non block based AMs would be, so
there
- * isn't one yet.
+ * This callback needs to fill reservour with sample rows during analyze
+ * scan.
*/
- bool (*scan_analyze_next_block) (TableScanDesc scan,
-
BlockNumber blockno,
-
BufferAccessStrategy bstrategy);
-
- /*
- * See table_scan_analyze_next_tuple().
- *
- * Not every AM might have a meaningful concept of dead rows, in which
- * case it's OK to not increment *deadrows - but note that that may
- * influence autovacuum scheduling (see comment for relation_vacuum
- * callback).
- */
- bool (*scan_analyze_next_tuple) (TableScanDesc scan,
-
TransactionId OldestXmin,
-
double *liverows,
-
double *deadrows,
-
TupleTableSlot *slot);
+ int (*acquire_sample_rows) (TableScanDesc scan,
+
int elevel,
+
int natts,
+
VacAttrStats **stats,
+
BufferAccessStrategy bstrategy,
+
HeapTuple *rows,
+
int targrows,
+
double *totalrows,
+
double *totaldeadrows);
/* see table_index_build_range_scan for reference about parameters */
double (*index_build_range_scan) (Relation table_rel,
@@ -1485,40 +1465,18 @@ table_relation_vacuum(Relation rel, struct VacuumParams
*params,
rel->rd_tableam->relation_vacuum(rel, params, bstrategy);
}
-/*
- * Prepare to analyze block `blockno` of `scan`. The scan needs to have been
- * started with table_beginscan_analyze(). Note that this routine might
- * acquire resources like locks that are held until
- * table_scan_analyze_next_tuple() returns false.
- *
- * Returns false if block is unsuitable for sampling, true otherwise.
- */
-static inline bool
-table_scan_analyze_next_block(TableScanDesc scan, BlockNumber blockno,
- BufferAccessStrategy
bstrategy)
+static inline int
+table_acquire_sample_rows(TableScanDesc scan, int elevel,
+ int natts, VacAttrStats
**stats,
+ BufferAccessStrategy
bstrategy,
+ HeapTuple *rows, int targrows,
+ double *totalrows, double
*totaldeadrows)
{
- return scan->rs_rd->rd_tableam->scan_analyze_next_block(scan, blockno,
-
bstrategy);
-}
-
-/*
- * Iterate over tuples in the block selected with
- * table_scan_analyze_next_block() (which needs to have returned true, and
- * this routine may not have returned false for the same block before). If a
- * tuple that's suitable for sampling is found, true is returned and a tuple
- * is stored in `slot`.
- *
- * *liverows and *deadrows are incremented according to the encountered
- * tuples.
- */
-static inline bool
-table_scan_analyze_next_tuple(TableScanDesc scan, TransactionId OldestXmin,
- double *liverows,
double *deadrows,
- TupleTableSlot *slot)
-{
- return scan->rs_rd->rd_tableam->scan_analyze_next_tuple(scan,
OldestXmin,
-
liverows, deadrows,
-
slot);
+ return scan->rs_rd->rd_tableam->acquire_sample_rows(scan, elevel,
+
natts, stats,
+
bstrategy, rows,
+
targrows, totalrows,
+
totaldeadrows);
}
/*
diff --git a/src/include/commands/progress.h b/src/include/commands/progress.h
index 36b073e677..397c8612d4 100644
--- a/src/include/commands/progress.h
+++ b/src/include/commands/progress.h
@@ -36,13 +36,11 @@
/* Progress parameters for analyze */
#define PROGRESS_ANALYZE_PHASE 0
-#define PROGRESS_ANALYZE_BLOCKS_TOTAL 1
-#define PROGRESS_ANALYZE_BLOCKS_DONE 2
-#define PROGRESS_ANALYZE_EXT_STATS_TOTAL 3
-#define PROGRESS_ANALYZE_EXT_STATS_COMPUTED 4
-#define PROGRESS_ANALYZE_CHILD_TABLES_TOTAL 5
-#define PROGRESS_ANALYZE_CHILD_TABLES_DONE 6
-#define PROGRESS_ANALYZE_CURRENT_CHILD_TABLE_RELID 7
+#define PROGRESS_ANALYZE_EXT_STATS_TOTAL 1
+#define PROGRESS_ANALYZE_EXT_STATS_COMPUTED 2
+#define PROGRESS_ANALYZE_CHILD_TABLES_TOTAL 3
+#define PROGRESS_ANALYZE_CHILD_TABLES_DONE 4
+#define PROGRESS_ANALYZE_CURRENT_CHILD_TABLE_RELID 5
/* Phases of analyze (as advertised via PROGRESS_ANALYZE_PHASE) */
#define PROGRESS_ANALYZE_PHASE_ACQUIRE_SAMPLE_ROWS 1
diff --git a/src/include/foreign/fdwapi.h b/src/include/foreign/fdwapi.h
index 95556dfb15..f056d02b4a 100644
--- a/src/include/foreign/fdwapi.h
+++ b/src/include/foreign/fdwapi.h
@@ -13,6 +13,7 @@
#define FDWAPI_H
#include "access/parallel.h"
+#include "commands/vacuum.h"
#include "nodes/execnodes.h"
#include "nodes/pathnodes.h"
@@ -140,6 +141,7 @@ typedef void (*ExplainDirectModify_function)
(ForeignScanState *node,
struct ExplainState *es);
typedef int (*AcquireSampleRowsFunc) (Relation relation, int elevel,
+ int
natts, VacAttrStats **stats,
HeapTuple *rows, int targrows,
double *totalrows,
double *totaldeadrows);
> 7 дек. 2020 г., в 23:23, Смирнов Денис <[email protected]> написал(а):
>
> Hello all!
>
> I suggest a refactoring of analyze AM API as it is too much heap specific at
> the moment. The problem was inspired by Greenplum’s analyze improvement for
> append-optimized row and column AM with variable size compressed blocks.
> Currently we do analyze in two steps.
>
> 1. Sample fix size blocks with algorithm S from Knuth (BlockSampler function)
> 2. Collect tuples into reservoir with algorithm Z from Vitter.
>
> So this doesn’t work for AMs using variable sized physical blocks for
> example. They need weight random sampling (WRS) algorithms like A-Chao or
> logical blocks to follow S-Knuth (and have a problem with
> RelationGetNumberOfBlocks() estimating a physical number of blocks). Another
> problem with columns - they are not passed to analyze begin scan and can’t
> benefit from column storage at ANALYZE TABLE (COL).
>
> The suggestion is to replace table_scan_analyze_next_block() and
> table_scan_analyze_next_tuple() with a single function:
> table_acquire_sample_rows(). The AM implementation of
> table_acquire_sample_rows() can use the BlockSampler functions if it wants
> to, but if the AM is not block-oriented, it could do something else. This
> suggestion also passes VacAttrStats to table_acquire_sample_rows() for
> column-oriented AMs and removes PROGRESS_ANALYZE_BLOCKS_TOTAL and
> PROGRESS_ANALYZE_BLOCKS_DONE definitions as not all AMs can be block-oriented.
>
> <am-analyze-1.patch>
>
>
>
> Best regards,
> Denis Smirnov | Developer
> [email protected]
> Arenadata | Godovikova 9-17, Moscow 129085 Russia
>