/explain/freeze

freeze

Transaction ids are 32-bit and wrap. A row whose xmin falls more than 2^31 transactions behind the current xid would appear to be in the future, so Postgres must mark old rows frozen (permanently visible, their xmin no longer compared) before that happens. Freezing is vacuum’s second job, and the quiet one: it happens per page, it dirties the page, and its schedule is controlled by three age settings that only make sense together.

DEMO — xid age over 365 d, toy tablesame chart system as the report
2,147,483,647 (wraparound)freeze_max_age = 200,000,000
day 090180270365
autovacuum_freeze_max_age200,000,000
default 200,000,000 · max 2,000,000,000
xid consumption40.00 M/day
transactions per day, 1 M → 400 M
AGGRESSIVE VACUUM EVERY
5.0 d
RUNS PER YEAR
73.0
MARGIN TO SHUTDOWN
48.7 d
SEE ALSO
vacuum_freeze_min_ageaggressive vacuumwraparound← back to start
Since Postgres 16 whole pages freeze at once when it is cheap (the WAL is already being written); Postgres 18 adds eager freezing of all-visible pages during normal vacuums.
freeze — robovac