Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 030cdaf

Browse files
committed
Fix a missed case in code for "moving average" estimate of reltuples.
It is possible for VACUUM to scan no pages at all, if the visibility map shows that all pages are all-visible. In this situation VACUUM has no new information to report about the relation's tuple density, so it wasn't changing pg_class.reltuples ... but it updated pg_class.relpages anyway. That's wrong in general, since there is no evidence to justify changing the density ratio reltuples/relpages, but it's particularly bad if the previous state was relpages=reltuples=0, which means "unknown tuple density". We just replaced "unknown" with "zero". ANALYZE would eventually recover from this, but it could take a lot of repetitions of ANALYZE to do so if the relation size is much larger than the maximum number of pages ANALYZE will scan, because of the moving-average behavior introduced by commit b4b6923. The only known situation where we could have relpages=reltuples=0 and yet the visibility map asserts everything's visible is immediately following a pg_upgrade. It might be advisable for pg_upgrade to try to preserve the relpages/reltuples statistics; but in any case this code is wrong on its own terms, so fix it. Per report from Sergey Koposov. Back-patch to 8.4, where the visibility map was introduced, same as the previous change.
1 parent 5795773 commit 030cdaf

File tree

3 files changed

+37
-11
lines changed

3 files changed

+37
-11
lines changed

src/backend/commands/vacuum.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,9 @@ vac_estimate_reltuples(Relation relation, bool is_analyze,
484484

485485
/*
486486
* If scanned_pages is zero but total_pages isn't, keep the existing value
487-
* of reltuples.
487+
* of reltuples. (Note: callers should avoid updating the pg_class
488+
* statistics in this situation, since no new information has been
489+
* provided.)
488490
*/
489491
if (scanned_pages == 0)
490492
return old_rel_tuples;

src/backend/commands/vacuumlazy.c

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ typedef struct LVRelStats
8484
/* hasindex = true means two-pass strategy; false means one-pass */
8585
bool hasindex;
8686
/* Overall statistics about rel */
87+
BlockNumber old_rel_pages; /* previous value of pg_class.relpages */
8788
BlockNumber rel_pages; /* total number of pages */
8889
BlockNumber scanned_pages; /* number of pages we examined */
8990
double scanned_tuples; /* counts only tuples on scanned pages */
@@ -154,6 +155,9 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
154155
TimestampTz starttime = 0;
155156
bool scan_all;
156157
TransactionId freezeTableLimit;
158+
BlockNumber new_rel_pages;
159+
double new_rel_tuples;
160+
TransactionId new_frozen_xid;
157161

158162
pg_rusage_init(&ru0);
159163

@@ -176,6 +180,7 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
176180

177181
vacrelstats = (LVRelStats *) palloc0(sizeof(LVRelStats));
178182

183+
vacrelstats->old_rel_pages = onerel->rd_rel->relpages;
179184
vacrelstats->old_rel_tuples = onerel->rd_rel->reltuples;
180185
vacrelstats->num_index_scans = 0;
181186

@@ -205,20 +210,39 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
205210
FreeSpaceMapVacuum(onerel);
206211

207212
/*
208-
* Update statistics in pg_class. But don't change relfrozenxid if we
209-
* skipped any pages.
213+
* Update statistics in pg_class.
214+
*
215+
* A corner case here is that if we scanned no pages at all because every
216+
* page is all-visible, we should not update relpages/reltuples, because
217+
* we have no new information to contribute. In particular this keeps
218+
* us from replacing relpages=reltuples=0 (which means "unknown tuple
219+
* density") with nonzero relpages and reltuples=0 (which means "zero
220+
* tuple density") unless there's some actual evidence for the latter.
221+
*
222+
* Also, don't change relfrozenxid if we skipped any pages, since then
223+
* we don't know for certain that all tuples have a newer xmin.
210224
*/
225+
new_rel_pages = vacrelstats->rel_pages;
226+
new_rel_tuples = vacrelstats->new_rel_tuples;
227+
if (vacrelstats->scanned_pages == 0 && new_rel_pages > 0)
228+
{
229+
new_rel_pages = vacrelstats->old_rel_pages;
230+
new_rel_tuples = vacrelstats->old_rel_tuples;
231+
}
232+
233+
new_frozen_xid = FreezeLimit;
234+
if (vacrelstats->scanned_pages < vacrelstats->rel_pages)
235+
new_frozen_xid = InvalidTransactionId;
236+
211237
vac_update_relstats(onerel,
212-
vacrelstats->rel_pages, vacrelstats->new_rel_tuples,
238+
new_rel_pages, new_rel_tuples,
213239
vacrelstats->hasindex,
214-
(vacrelstats->scanned_pages < vacrelstats->rel_pages) ?
215-
InvalidTransactionId :
216-
FreezeLimit);
240+
new_frozen_xid);
217241

218242
/* report results to the stats collector, too */
219243
pgstat_report_vacuum(RelationGetRelid(onerel),
220244
onerel->rd_rel->relisshared,
221-
vacrelstats->new_rel_tuples);
245+
new_rel_tuples);
222246

223247
/* and log the action if appropriate */
224248
if (IsAutoVacuumWorkerProcess() && Log_autovacuum_min_duration >= 0)
@@ -238,7 +262,7 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
238262
vacrelstats->pages_removed,
239263
vacrelstats->rel_pages,
240264
vacrelstats->tuples_deleted,
241-
vacrelstats->new_rel_tuples,
265+
new_rel_tuples,
242266
pg_rusage_show(&ru0))));
243267
}
244268
}

src/backend/utils/cache/relcache.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1415,8 +1415,8 @@ formrdesc(const char *relationName, Oid relationReltype,
14151415
/* formrdesc is used only for permanent relations */
14161416
relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
14171417

1418-
relation->rd_rel->relpages = 1;
1419-
relation->rd_rel->reltuples = 1;
1418+
relation->rd_rel->relpages = 0;
1419+
relation->rd_rel->reltuples = 0;
14201420
relation->rd_rel->relkind = RELKIND_RELATION;
14211421
relation->rd_rel->relhasoids = hasoids;
14221422
relation->rd_rel->relnatts = (int16) natts;

0 commit comments

Comments
 (0)