Bloat là phần dung lượng index bị chiếm bởi entry chết hoặc trang chỉ dùng một phần. Nó phát sinh từ mô hình MVCC của PostgreSQL: mỗi UPDATE tạo một phiên bản dòng mới thay vì sửa tại chỗ, kèm entry index mới. Entry cũ chỉ được autovacuum đánh dấu tái sử dụng, nhưng trang index đã cấp phát thì không trả lại cho hệ điều hành.
Hậu quả trên bảng bị UPDATE/DELETE liên tục (bảng hàng đợi, bảng session): index có thể lớn gấp nhiều lần dữ liệu thực, làm tăng lượng đĩa phải đọc và giảm hiệu quả cache.
Đo mức độ: dùng extension pgstattuple (pgstatindex()) để lấy avg_leaf_density — mật độ thấp bất thường là dấu hiệu bloat. Các truy vấn ước lượng bloat trên PostgreSQL Wiki dùng được nhưng chỉ là xấp xỉ.
Xử lý:
-- PostgreSQL 12+: rebuild without blocking writes
REINDEX INDEX CONCURRENTLY idx_orders_status;
REINDEX TABLE CONCURRENTLY orders;REINDEX không CONCURRENTLY sẽ khoá ghi trên bảng suốt quá trình dựng lại — tránh trên production. VACUUM FULL cũng dọn sạch nhưng lấy khoá ACCESS EXCLUSIVE, chặn cả đọc.
Phòng hơn chữa: chỉnh autovacuum tích cực hơn cho bảng ghi nhiều (autovacuum_vacuum_scale_factor nhỏ lại), giảm số index không cần thiết, và cân nhắc fillfactor thấp hơn trên bảng update nhiều để tạo điều kiện cho HOT update.