PostgreSQL updates and deletes leave old tuple versions until vacuum can reclaim their space for reuse. Autovacuum also updates visibility information and prevents transaction-ID wraparound. Bloat occurs when allocated table or index space is poorly utilized; its cause matters more than its label. Long transactions, write patterns, thresholds, and maintenance capacity determine health.
MVCC keeps old row versions for snapshots. Vacuum identifies versions no longer visible to any relevant transaction and marks space reusable. Normal vacuum usually does not shrink the table file; rewrite-style operations can return space but require disruptive planning.
Statistics are estimates and can reset. Combine them with table/index size, workload, logs, progress views, and supported extensions/tools.
High-churn tables may need lower per-table scale factors/thresholds or more maintenance capacity. Do not disable autovacuum; wraparound protection is mandatory.
Re-embedding millions of chunks creates update/delete churn, new indexes, and WAL. Prefer versioned batch replacement with observable cleanup. Long model/evaluation jobs must not wrap all work in one database transaction, or they can block cleanup for hours.
In a disposable table, insert and update many rows, inspect statistics, run VACUUM (ANALYZE) outside a transaction block, and compare. Show that logical cleanup and file shrink are different claims.
Design maintenance for a chunk table replaced in batches during re-embedding.
Acceptance criterion: batches are short, old versions have lifecycle state, cleanup is monitored, and no job holds a transaction for the full rebuild.