Vacuum at the Page Level

Postgres fans are obsessed with the tiny page drama hiding behind “healthy” cleanup

TLDR: The article shows, step by step, why deleted rows in PostgreSQL don’t magically free space right away and how the cleanup process really works. Commenters fixated on the bigger drama: one forgotten open session can quietly block cleanup, making a database swell while everything looks “fine” on paper.

A deeply nerdy post about how PostgreSQL cleans up deleted data somehow turned into a surprisingly spicy community therapy session. The article itself is a microscope-level tour of what happens before and after rows get deleted: first everything looks neat, then some rows are marked dead, and then the database’s cleanup worker, VACUUM, has to step in and reclaim space. In plain English: deleting something from a database often doesn’t instantly make the storage shrink, and this post shows exactly why, byte by byte, like a forensic crime show for data.

But the real heat came from the comments, where readers zeroed in on the classic nightmare scenario: the cleanup process keeps running, yet the table keeps getting fatter. Commenter haeseong basically summed up the communal groan: one forgotten open connection or abandoned replication setup can block cleanup, making the system look busy while accomplishing almost nothing. That landed hard because it’s the kind of invisible problem that makes engineers question their life choices.

The mood was equal parts admiration and dread. Some praised the article for finally making a notoriously confusing failure mode understandable. Others turned it into gallows humor, joking that the true villain in every database horror story is that one idle transaction just sitting there, doing nothing, ruining everyone’s week. The vibe: part classroom, part support group, part public shaming for whoever left the cleanup blocked.

Key Points

  • The article explains that PostgreSQL page pruning is limited to single-page cleanup of HOT-updated tuples, while VACUUM is needed for broader cleanup tasks.
  • A demo table with 50 rows and a primary key index is created to observe VACUUM behavior in a table where indexes matter.
  • The article uses the PostgreSQL extensions `pageinspect`, `pg_visibility`, and `pg_freespacemap` to inspect page, visibility, and free-space metadata.
  • A baseline snapshot of page 0 shows page header values, line pointers, tuple lengths, and tuple header fields in a clean pre-delete state.
  • The article deletes 16 rows with `DELETE FROM vacuum_demo WHERE id % 3 = 0` to create dead tuples for later before-and-after VACUUM inspection.

Hottest takes

"one forgotten idle transaction" — haeseong
"every autovacuum pass does a full scan while reclaiming almost nothing" — haeseong
"When a table keeps bloating even though autovacuum looks healthy" — haeseong
Made with <3 by @siedrix and @shesho from CDMX. Powered by Forge&Hive.