Skip to content
dbexplore

Question: Vacuum, bloat and wraparound

What is the difference between VACUUM and ANALYZE?

Answered in the first paragraph. Last updated .

VACUUM is housekeeping on the storage: it makes the space held by no-longer-visible row versions reusable, advances the freezing bookkeeping that keeps transaction ids from wrapping, and records which pages are entirely visible. ANALYZE is housekeeping on the planner’s knowledge: it samples rows and stores a statistical summary so the optimiser can estimate how many rows a condition will match. Neither substitutes for the other.

Separate jobs, separate triggers, separate symptoms

Autovacuum performs both, which is why they get conflated, but it decides on each independently. A table earns a vacuum by accumulating changes that make rows invisible, and it earns an analyze by accumulating changes at all, including inserts that create no garbage whatsoever. An append-only table therefore needs analyzing far more often than it needs vacuuming, and a table churned by updates needs both.

The symptoms are nothing alike. Skipped vacuuming shows up as a file that grows without the row count growing, as scans reading pages full of nothing, and eventually as warnings about the age of the oldest unfrozen id. Skipped analyzing shows up as plans, and only as plans: a join in the wrong order, a sequential scan where an index would have served, a nested loop chosen on an estimate of one row that turns out to be a million.

That asymmetry matters after any bulk operation. Loading several million rows leaves the statistics describing the table as it was before the load, and the first report anybody runs afterwards is planned against a table that no longer exists. Running ANALYZE by hand at the end of a load is cheap and it is the single most reliable way to avoid the phone call.

Locks, cost and the combined form

Both take the same weak table lock and both run concurrently with reads and writes, so neither is a maintenance-window operation. Sampling is the cheaper of the two by a wide margin: it reads a bounded sample of pages rather than the whole relation, which is why it is safe to run manually and immediately whenever you suspect the estimates are stale.

VACUUM ANALYZE runs them in that order in one statement. It is a convenience, not a third thing, and the reason to reach for it is a table that has just been through both kinds of change at once.

When bloat is the problem the treatment is in autovacuum and table bloat. When the planner is the problem, the estimate to check first is the one at the bottom of the plan, and unused and missing indexes covers reading that correctly.

Put every Postgres you run on autopilot.

We onboard teams in small batches. Tell us about your fleet and we will reach out when a seat opens. One email, no drip campaign.