Skip to content

Commit 3097bde

Browse files
Avoid reltuples distortion in very small tables.
Consistently avoid trusting a sample of only one page at the point that VACUUM determines a new reltuples for the target table (though only when the table is larger than a single page). This is follow-up work to commit 74388a1, which added a heuristic to prevent reltuples from becoming distorted by successive VACUUM operations that each scan only a single heap page (which was itself more or less a bugfix for an issue in commit 44fa848, which simplified VACUUM's handling of scanned pages). The original bugfix commit did not account for certain remaining cases that where not affected by its "2% of total relpages" heuristic. This happened with relations that are small enough that just one of its pages exceeded the 2% threshold, yet still big enough for VACUUM to deem skipping most of its pages via the visibility map worthwhile. reltuples could still become distorted over time with such a table, at least in scenarios where the VACUUM command is run repeatedly and without the table itself ever changing. Author: Peter Geoghegan <[email protected]> Discussion: https://postgr.es/m/CAH2-Wzk7d4m3oEbEWkWQKd+gz-eD_peBvdXVk1a_KBygXadFeg@mail.gmail.com Backpatch: 15-, where the rules for scanned pages changed.
1 parent 7d12693 commit 3097bde

File tree

1 file changed

+10
-16
lines changed

1 file changed

+10
-16
lines changed

src/backend/commands/vacuum.c

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1234,31 +1234,25 @@ vac_estimate_reltuples(Relation relation,
12341234
if (scanned_pages >= total_pages)
12351235
return scanned_tuples;
12361236

1237-
/*
1238-
* If scanned_pages is zero but total_pages isn't, keep the existing value
1239-
* of reltuples. (Note: we might be returning -1 in this case.)
1240-
*/
1241-
if (scanned_pages == 0)
1242-
return old_rel_tuples;
1243-
12441237
/*
12451238
* When successive VACUUM commands scan the same few pages again and
12461239
* again, without anything from the table really changing, there is a risk
12471240
* that our beliefs about tuple density will gradually become distorted.
1248-
* It's particularly important to avoid becoming confused in this way due
1249-
* to vacuumlazy.c implementation details. For example, the tendency for
1250-
* our caller to always scan the last heap page should not ever cause us
1251-
* to believe that every page in the table must be just like the last
1252-
* page.
1241+
* This might be caused by vacuumlazy.c implementation details, such as
1242+
* its tendency to always scan the last heap page. Handle that here.
1243+
*
1244+
* If the relation is _exactly_ the same size according to the existing
1245+
* pg_class entry, and only a few of its pages (less than 2%) were
1246+
* scanned, keep the existing value of reltuples. Also keep the existing
1247+
* value when only a subset of rel's pages <= a single page were scanned.
12531248
*
1254-
* We apply a heuristic to avoid these problems: if the relation is
1255-
* exactly the same size as it was at the end of the last VACUUM, and only
1256-
* a few of its pages (less than a quasi-arbitrary threshold of 2%) were
1257-
* scanned by this VACUUM, assume that reltuples has not changed at all.
1249+
* (Note: we might be returning -1 here.)
12581250
*/
12591251
if (old_rel_pages == total_pages &&
12601252
scanned_pages < (double) total_pages * 0.02)
12611253
return old_rel_tuples;
1254+
if (scanned_pages <= 1)
1255+
return old_rel_tuples;
12621256

12631257
/*
12641258
* If old density is unknown, we can't do much except scale up

0 commit comments

Comments
 (0)