Concepts·PostgreSQL
PostgreSQL VACUUM and Table Bloat
An UPDATE of 133,333 rows leaves 133,333 dead tuples. `VACUUM` clears them and the table stays at exactly 47 MB. Only `VACUUM FULL` returns space - and it rewrites the whole table under an exclusive lock to do it.
Performance Guide 35 of 47 Advanced
- OSUbuntu 26.04 LTS (resolute)
- PostgreSQL18.6-0ubuntu0.26.04.1
- Test data400,000 rows, 2 core / 4 GB host
- TimeAbout 17 min
- Reviewed27 August 2026
Written against the versions above. This is a direct consequence of MVCC: an UPDATE writes a new row version and leaves the old one for concurrent readers. Every PostgreSQL table works this way, and autovacuum exists to manage it.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| db-a01 | 192.168.0.81 | Ubuntu 26.04 LTS | Primary / Source / Replica Set Member 1 | 2 Core | 4 GB | 50 GB |
Before you start
- The
eventstable with 400,000 rows.
-
Update a third of the rows and count the dead ones
-
Vacuum, and watch the size not change
-
Rewrite the table to get the space back
-
Read the settings that make this automatic