AdvancedPerformance & Indexes

Index bloat detection and maintenance

The query

SQL
-- Find bloated indexes
SELECT
  schemaname,
  tablename,
  indexname,
  pg_size_pretty(pg_relation_size(indexrelid)) AS index_size,
  idx_scan AS index_scans,
  idx_tup_read AS rows_read
FROM pg_stat_user_indexes
ORDER BY pg_relation_size(indexrelid) DESC;

-- Rebuild bloated index online (no table lock!)
REINDEX INDEX CONCURRENTLY idx_emp_email;

-- Check unused indexes
SELECT schemaname, tablename, indexname
FROM pg_stat_user_indexes
WHERE idx_scan = 0
  AND NOT EXISTS (
    SELECT 1 FROM pg_constraint
    WHERE conindid = indexrelid
  );
Tested against PostgreSQL 16

Note

REINDEX CONCURRENTLY (PostgreSQL 12+) rebuilds without blocking reads/writes. Drop unused indexes — they slow writes!