diff options
author | Tom Lane | 2020-08-30 16:21:51 +0000 |
---|---|---|
committer | Tom Lane | 2020-08-30 16:21:51 +0000 |
commit | 3d351d916b20534f973eda760cde17d96545d4c4 (patch) | |
tree | 133283e6cd7c7308add384bd7fd5d037801ac683 /src/backend/commands/vacuum.c | |
parent | 9511fb37ac78c77736e5483118265f7e83cd9f3c (diff) |
Redefine pg_class.reltuples to be -1 before the first VACUUM or ANALYZE.
Historically, we've considered the state with relpages and reltuples
both zero as indicating that we do not know the table's tuple density.
This is problematic because it's impossible to distinguish "never yet
vacuumed" from "vacuumed and seen to be empty". In particular, a user
cannot use VACUUM or ANALYZE to override the planner's normal heuristic
that an empty table should not be believed to be empty because it is
probably about to get populated. That heuristic is a good safety
measure, so I don't care to abandon it, but there should be a way to
override it if the table is indeed intended to stay empty.
Hence, represent the initial state of ignorance by setting reltuples
to -1 (relpages is still set to zero), and apply the minimum-ten-pages
heuristic only when reltuples is still -1. If the table is empty,
VACUUM or ANALYZE (but not CREATE INDEX) will override that to
reltuples = relpages = 0, and then we'll plan on that basis.
This requires a bunch of fiddly little changes, but we can get rid of
some ugly kluges that were formerly needed to maintain the old definition.
One notable point is that FDWs' GetForeignRelSize methods will see
baserel->tuples = -1 when no ANALYZE has been done on the foreign table.
That seems like a net improvement, since those methods were formerly
also in the dark about what baserel->tuples = 0 really meant. Still,
it is an API change.
I bumped catversion because code predating this change would get confused
by seeing reltuples = -1.
Discussion: https://postgr.es/m/[email protected]
Diffstat (limited to 'src/backend/commands/vacuum.c')
-rw-r--r-- | src/backend/commands/vacuum.c | 14 |
1 files changed, 6 insertions, 8 deletions
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 23eb605d4cb..308a51d95d7 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -1128,8 +1128,8 @@ vacuum_set_xid_limits(Relation rel, * live tuples seen; but if we did not, we should not blindly extrapolate * from that number, since VACUUM may have scanned a quite nonrandom * subset of the table. When we have only partial information, we take - * the old value of pg_class.reltuples as a measurement of the - * tuple density in the unscanned pages. + * the old value of pg_class.reltuples/pg_class.relpages as a measurement + * of the tuple density in the unscanned pages. * * Note: scanned_tuples should count only *live* tuples, since * pg_class.reltuples is defined that way. @@ -1152,18 +1152,16 @@ vac_estimate_reltuples(Relation relation, /* * If scanned_pages is zero but total_pages isn't, keep the existing value - * of reltuples. (Note: callers should avoid updating the pg_class - * statistics in this situation, since no new information has been - * provided.) + * of reltuples. (Note: we might be returning -1 in this case.) */ if (scanned_pages == 0) return old_rel_tuples; /* - * If old value of relpages is zero, old density is indeterminate; we - * can't do much except scale up scanned_tuples to match total_pages. + * If old density is unknown, we can't do much except scale up + * scanned_tuples to match total_pages. */ - if (old_rel_pages == 0) + if (old_rel_tuples < 0 || old_rel_pages == 0) return floor((scanned_tuples / scanned_pages) * total_pages + 0.5); /* |