Detection:- Start with metrics and planner signs: rising index scans taking longer, increased sequential scans, planner choosing seq scan over index, higher planner_cost estimates.- Inspect index vs table bloat with queries (Postgres example using pg_stat and pgstattuple):sql
-- approximate index size vs live tuples
SELECT
schemaname, relname, indexrelname,
pg_relation_size(indexrelid) AS idx_bytes,
idx_scan, idx_tup_read, idx_tup_fetch
FROM pg_stat_all_indexes
WHERE schemaname NOT IN ('pg_catalog','information_schema');
-- precise bloat estimate (requires pgstattuple)
SELECT * FROM pgstattuple('my_index');
- Look for high dead_tuple ratios, large index size with low live tuples, or vacuum_deadlocks in logs. Tools: pgstattuple, pg_freespace, pg_repack, and monitoring (I/O, latency).Maintenance options and when to use them:1. VACUUM (plain / ANALYZE)- What: Reclaims some dead row space, updates stats.- Use when: regular MVCC churn; planner misestimates due to outdated stats.- Operational impact: non-blocking for reads/writes; uses I/O and CPU; autovacuum should handle most cases. VACUUM VERBOSE shows progress.2. VACUUM FULL- What: Rewrites table and indexes to compact; exclusive lock.- Use when: extreme bloat and cannot wait for offline window.- Operational impact: takes ACCESS EXCLUSIVE lock on table — blocks reads/writes (downtime), heavy I/O. Schedule during maintenance window.3. REINDEX- What: Rebuilds one or more indexes.- Use when: index bloat, corrupted index, or many dead index tuples.- Operational impact: default REINDEX acquires exclusive lock on index’s parent table (blocks writes and possibly reads). Postgres supports REINDEX CONCURRENTLY (versions >12) which reduces locking but still uses more time/IO. Reindexing is less intrusive than VACUUM FULL for large tables when targeting just indexes.4. CLUSTER (or pg_repack)- What: Physically reorder table by index, rebuilds table and indexes.- Use when: want to improve locality for frequent range scans (BI queries), reduce bloat.- Operational impact: CLUSTER acquires exclusive lock on table for entire operation (downtime). pg_repack can do same without long exclusive locks by copying and swapping; requires extra disk space.Operational considerations for BI production:- Prioritize non-blocking options first: autovacuum tuning, VACUUM (regular), REINDEX CONCURRENTLY, and pg_repack to avoid downtime.- Resource planning: all rebuilds are I/O and CPU heavy — throttle via maintenance_work_mem, vacuum_cost_* settings, schedule during low BI usage windows (nights/weekends).- Disk space: rebuilding needs extra space (about size of table/index). Ensure free space before starting.- Stats & planner: always run ANALYZE after rebuilds so planner uses fresh stats.- Rollout strategy: start with most-bloated indexes, test on staging, notify stakeholders of potential query latency, and have rollback/maintenance windows for VACUUM FULL or CLUSTER.- Monitoring: watch long-running locks (pg_locks), I/O saturation, and query performance post-maintenance.Example small plan: tune autovacuum thresholds for high-churn reporting tables, run REINDEX CONCURRENTLY on largest indexes during off-peak, use pg_repack for tables needing clustering, reserve VACUUM FULL/CLUSTER for critical maintenance windows.