Skip to content

Commit 269efd0

Browse files
committed
Avoid having vacuum set reltuples to 0 on non-empty relations in the
presence of page pins, which leads to serious estimation errors in the planner. This particularly affects small heavily-accessed tables, especially where locking (e.g. from FK constraints) forces frequent vacuums for mxid cleanup. Fix by keeping separate track of pages whose live tuples were actually counted vs. pages that were only scanned for freezing purposes. Thus, reltuples can only be set to 0 if all pages of the relation were actually counted. Backpatch to all supported versions. Per bug #14057 from Nicolas Baccelli, analyzed by me. Discussion: https://postgr.es/m/20160331103739.8956.94469@wrigleys.postgresql.org
1 parent e0c8bd7 commit 269efd0

File tree

1 file changed

+11
-4
lines changed

1 file changed

+11
-4
lines changed

src/backend/commands/vacuumlazy.c

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ typedef struct LVRelStats
104104
BlockNumber old_rel_pages; /* previous value of pg_class.relpages */
105105
BlockNumber rel_pages; /* total number of pages */
106106
BlockNumber scanned_pages; /* number of pages we examined */
107-
double scanned_tuples; /* counts only tuples on scanned pages */
107+
BlockNumber tupcount_pages; /* pages whose tuples we counted */
108+
double scanned_tuples; /* counts only tuples on tupcount_pages */
108109
double old_rel_tuples; /* previous value of pg_class.reltuples */
109110
double new_rel_tuples; /* new estimated total # of tuples */
110111
double new_dead_tuples; /* new estimated total # of dead tuples */
@@ -281,6 +282,10 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
281282
* density") with nonzero relpages and reltuples=0 (which means "zero
282283
* tuple density") unless there's some actual evidence for the latter.
283284
*
285+
* It's important that we use tupcount_pages and not scanned_pages for the
286+
* check described above; scanned_pages counts pages where we could not get
287+
* cleanup lock, and which were processed only for frozenxid purposes.
288+
*
284289
* We do update relallvisible even in the corner case, since if the table
285290
* is all-visible we'd definitely like to know that. But clamp the value
286291
* to be not more than what we're setting relpages to.
@@ -290,7 +295,7 @@ lazy_vacuum_rel(Relation onerel, VacuumStmt *vacstmt,
290295
*/
291296
new_rel_pages = vacrelstats->rel_pages;
292297
new_rel_tuples = vacrelstats->new_rel_tuples;
293-
if (vacrelstats->scanned_pages == 0 && new_rel_pages > 0)
298+
if (vacrelstats->tupcount_pages == 0 && new_rel_pages > 0)
294299
{
295300
new_rel_pages = vacrelstats->old_rel_pages;
296301
new_rel_tuples = vacrelstats->old_rel_tuples;
@@ -455,6 +460,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
455460
nblocks = RelationGetNumberOfBlocks(onerel);
456461
vacrelstats->rel_pages = nblocks;
457462
vacrelstats->scanned_pages = 0;
463+
vacrelstats->tupcount_pages = 0;
458464
vacrelstats->nonempty_pages = 0;
459465
vacrelstats->latestRemovedXid = InvalidTransactionId;
460466

@@ -645,6 +651,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
645651
}
646652

647653
vacrelstats->scanned_pages++;
654+
vacrelstats->tupcount_pages++;
648655

649656
page = BufferGetPage(buf);
650657

@@ -1053,7 +1060,7 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
10531060
/* now we can compute the new value for pg_class.reltuples */
10541061
vacrelstats->new_rel_tuples = vac_estimate_reltuples(onerel, false,
10551062
nblocks,
1056-
vacrelstats->scanned_pages,
1063+
vacrelstats->tupcount_pages,
10571064
num_tuples);
10581065

10591066
/*
@@ -1357,7 +1364,7 @@ lazy_cleanup_index(Relation indrel,
13571364

13581365
ivinfo.index = indrel;
13591366
ivinfo.analyze_only = false;
1360-
ivinfo.estimated_count = (vacrelstats->scanned_pages < vacrelstats->rel_pages);
1367+
ivinfo.estimated_count = (vacrelstats->tupcount_pages < vacrelstats->rel_pages);
13611368
ivinfo.message_level = elevel;
13621369
ivinfo.num_heap_tuples = vacrelstats->new_rel_tuples;
13631370
ivinfo.strategy = vac_strategy;

0 commit comments

Comments
 (0)