Skip to content

Archive

Vacuum

7 articles
Database 15 Sep 2026 5 min read

PostgreSQL Visibility Map Tracks Heap Page State

PostgreSQL keeps tuple visibility metadata in heap rows, but checking every heap tuple is unnecessary when an entire page is already known to satisfy stronger conditions. A visibility map stores that page-level state in a compact relation fork. Each heap page has two corresponding bits. The all-visible bit records that every tuple on the page is visible to every current and future transaction. The all-frozen bit records that every tuple on the page is frozen. Those facts let PostgreSQL avoid work in index-only scans and vacuum operations without moving MVCC visibility data into indexes.

Database 15 Sep 2026 5 min read

PostgreSQL Visibility Map Controls Index-Only Heap Fetches

An Index Only Scan can still report heap fetches. The index may contain every value required by the query, yet PostgreSQL must also establish that each matching tuple is visible to the current MVCC snapshot. Index entries do not carry enough tuple-visibility state to make that decision independently. The visibility map supplies a page-level shortcut. When the heap page referenced by an index tuple is marked all-visible, the executor can accept the tuple’s visibility without reading that heap page. When the bit is clear, the executor visits the heap tuple and performs the normal visibility check.

Database 15 Sep 2026 6 min read

PostgreSQL Tuple Freezing Keeps Transaction IDs Comparable

PostgreSQL transaction IDs are 32-bit values, so the normal XID space eventually wraps. MVCC visibility still has to distinguish old row versions from transactions that have not happened yet. PostgreSQL resolves that finite-number problem by freezing sufficiently old tuple versions during vacuum processing. Freezing is not primarily a space-reclamation feature. It is a correctness mechanism that lets long-lived rows remain valid as the transaction counter continues around its finite range.

Database 15 Sep 2026 4 min read

PostgreSQL Multixact Vacuum Bounds Member Age

PostgreSQL can place more than one transaction behind a tuple’s xmax. This occurs when concurrent transactions hold compatible row-level locks on the same tuple. A single transaction ID cannot represent that set, so PostgreSQL records a multixact identifier that refers to members stored outside the heap tuple. That indirection creates its own age boundary. Multixact identifiers are finite, and their member records occupy SLRU-backed storage. Old tuple metadata therefore cannot retain multixact references indefinitely. VACUUM participates in keeping both identifier age and member storage bounded.

Database 15 Sep 2026 6 min read

PostgreSQL Frozen Pages Bound Transaction ID Maintenance

A PostgreSQL heap page can reach a state where anti-wraparound vacuum no longer needs to inspect its tuple transaction IDs. The visibility map records this state with the all-frozen bit, allowing later aggressive vacuum work to skip the page until a data change invalidates that fact. This is separate from reclaiming dead tuples. A table with little update or delete activity can still require vacuum work because transaction IDs have a finite comparison range. Freezing converts sufficiently old tuple transaction metadata into a form that remains valid across transaction ID wraparound.

Database 15 Sep 2026 6 min read

PostgreSQL BRIN Unsummarized Ranges Expand Heap Rechecks

A PostgreSQL BRIN index can contain block ranges with no summary tuple. Newly completed ranges do not receive an initial summary merely because inserts crossed the range boundary. Until maintenance creates that summary, a BRIN scan cannot use range metadata to exclude the affected heap pages. This state is normal index maintenance behavior rather than index corruption. It follows from BRIN’s compact design: the index stores summaries for groups of adjacent heap pages instead of one entry per indexed row.

Database 14 Sep 2026 5 min read

PostgreSQL Tuple Freezing Bounds XID Age

PostgreSQL transaction IDs are finite. A normal transaction ID occupies 32 bits, so the numeric counter eventually wraps and reuses values. MVCC visibility cannot treat those values as an ever-growing integer sequence. PostgreSQL instead compares normal transaction IDs in a circular space, where an ID can only remain safely classifiable as old for a bounded span. Tuple freezing removes that age dependency for row versions whose creating transactions are far enough in the past. VACUUM records the tuple as frozen, allowing PostgreSQL to treat its insertion as visible to every normal transaction without relying on the original transaction ID’s position in the circular XID space.