VACUUM, VACUUM FULL and ANALYZE
coreintermediateVACUUM reclaims dead tuple space for reuse. VACUUM FULL rewrites the whole table to reclaim space AND shrink the file, at the cost of an exclusive lock. ANALYZE is a separate job entirely: it collects statistics about a table's data distribution so the query planner can make good decisions — it does not touch dead tuples at all. VACUUM ANALYZE runs both together in one pass.
Think of it as
VACUUM and ANALYZE solve two unrelated problems that happen to run on the same schedule in practice: VACUUM is about reclaiming space and preventing bloat, while ANALYZE is about keeping the planner's picture of the data's shape (how many rows, how values are distributed) accurate enough to choose good query plans. A table can desperately need one without needing the other — a table with heavy UPDATE churn but a stable data distribution needs VACUUM more than ANALYZE, while a table that only grows via INSERT (no dead tuples) but whose row count has changed dramatically needs ANALYZE more than VACUUM.
What we're doing: Show a table where a stale row-count estimate (fixed by ANALYZE) causes a bad query plan, entirely independent of whether the table has any bloat.
- 1–2
- This table has no dead tuples at all — VACUUM would find nothing to do here.
- 4
- The planner's stale statistics, not any bloat, are the actual problem.
- 7–8
- ANALYZE alone — no VACUUM involved — is what fixes the plan.
-- before ANALYZE: plan based on stale row-count estimate
-- after ANALYZE: plan based on accurate current statisticsWhy this works: This table demonstrates the two concerns are genuinely independent — an INSERT-only table accumulates zero dead tuples (nothing for VACUUM to reclaim) but can still have wildly stale planner statistics if ANALYZE has not run recently, since row count and value distribution are ANALYZE's concern, not VACUUM's.
Running VACUUM and assuming it also refreshes planner statistics
Wrong
Better
What you see: Query plans remain poor immediately after a maintenance window that ran plain VACUUM, because the planner is still working from statistics gathered before a large data change — VACUUM alone never touched them.
Why: VACUUM and ANALYZE are separate operations that happen to be commonly run together — plain VACUUM with no ANALYZE keyword reclaims space only, leaving the planner's row-count and distribution statistics exactly as stale as they were before, which is why VACUUM ANALYZE (or autovacuum's combined behavior) is the usual recommendation rather than VACUUM alone.
- VACUUM / VACUUM FULL
- Reclaims dead tuple space
- VACUUM: reuse only, no lock; FULL: reuse + shrink, ACCESS EXCLUSIVE lock
- Never touches planner statistics
- ANALYZE
- Refreshes row-count and value-distribution statistics
- The query planner reads these to choose a plan
- Never touches dead tuples
VACUUM vs VACUUM FULL vs ANALYZE
Remember: VACUUM reclaims dead tuple space for reuse (not shrink). VACUUM FULL reclaims AND shrinks, at the cost of an ACCESS EXCLUSIVE lock. ANALYZE refreshes planner statistics — a completely separate concern from dead tuples. A table can need one badly without needing the other at all.
See also: how vacuum removes obsolete row versions · statistics collection and stale statistics

