Vacuum Basics
UPDATE and DELETE leave dead row versions until vacuum reclaims space and updates visibility maps. PostgreSQL 18.4 does not return file bytes to the OS immediately except in special cases.
Search across all documentation pages
UPDATE and DELETE leave dead row versions until vacuum reclaims space and updates visibility maps. PostgreSQL 18.4 does not return file bytes to the OS immediately except in special cases.
Quick-reference recipe card - copy-paste ready.
VACUUM (VERBOSE, ANALYZE) orders;
SELECT n_dead_tup, n_live_tup, last_vacuum, last_autovacuum
FROM pg_stat_user_tables
WHERE relname = 'orders';When to reach for this: Table grows after deletes, seq scans slow, or index-only scans stop appearing.
CREATE TABLE orders (
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
status text NOT NULL,
note text
);
INSERT INTO orders (status, note)
SELECT 'open', 'row-' || i FROM generate_series(1, 50000) i;
UPDATE orders SET status = 'closed' WHERE id % 2 = 0;
DELETE FROM orders WHERE id % 5 = 0;
SELECT relname, n_live_tup, n_dead_tup, last_vacuum
FROM pg_stat_user_tables
WHERE relname = 'orders';
VACUUM (VERBOSE) orders;
SELECT relname, n_live_tup, n_dead_tup, last_vacuum
FROM pg_stat_user_tables
WHERE relname = 'orders';What this demonstrates:
VACUUM marks space reusable inside the filepg_stat_user_tablesVACUUM FULL rewrites table exclusively (downtime risk); prefer pg_repack for online shrink.n_dead_tup thresholds.| Command | Effect |
|---|---|
VACUUM | Reclaim dead space in place |
VACUUM ANALYZE | Vacuum plus stats refresh |
VACUUM FREEZE | Aggressive freeze for wraparound |
VACUUM FULL | Exclusive lock, rewrites file |
EXPLAIN (ANALYZE, BUFFERS)
SELECT count(*) FROM orders WHERE status = 'open';
-- Index Only Scan needs fresh visibility map from vacuumpg_repack or partition drop for real shrink.idle_in_transaction_session_timeout.REINDEX CONCURRENTLY or repack.| Alternative | Use When | Don't Use When |
|---|---|---|
| Table partitioning | Drop old partitions instead of delete | Small dimension tables |
| pg_repack | Need disk shrink online | Simple vacuum suffices |
| Archive + truncate | Bulk historical purge | FK complexity |
When dead tuple thresholds hit per table settings and workers available.
No; uses ShareUpdateExclusiveLock compatible with DML.
Enables index-only scans when all tuples on page visible.
Prevents transaction id wraparound; critical for cluster health.
Throttles vacuum I/O via autovacuum_vacuum_cost_delay settings.
Large values in TOAST tables vacuum separately; see TOAST page.
pg_stat_user_tables plus pg_stat_progress_vacuum for active workers.
Auto handles steady state; manual after bulk ops or emergencies.
Standbys do not vacuum user tables; primary only.
Autovacuum tuning for hot tables.
Stack versions: This page was written for PostgreSQL 18.4 (stable 18, maintenance 17), pgvector 0.8+, PgBouncer 1.x, Patroni 3.x, and PostGIS 3.5+.
Reviewed by Chris St. John·Last updated Jul 18, 2026