Step-by-step method:1. Gather baseline metrics- Pull overall slow-query and resource stats (Postgres example): sql
SELECT query, calls, total_time, mean_time, rows
FROM pg_stat_statements
ORDER BY total_time DESC
LIMIT 50;
- Check table-level scans/hit ratios: sql
SELECT relname, seq_scan, idx_scan, n_tup_read, n_tup_ins
FROM pg_stat_user_tables;
2. Look for signals of missing indexes- High seq_scan counts on large tables (seq_scan >> idx_scan).- Queries with high total_time or mean_time and many calls.- EXPLAIN/EXPLAIN ANALYZE showing sequential scans, large estimated vs actual rows, or nested loop over large sets.- High CPU or I/O correlated to specific queries (monitoring tool or vmstat/iostat).- Frequent predicates on columns not covered by indexes (WHERE, JOIN, ORDER BY, GROUP BY).3. Drill into candidate queries- For top offenders run EXPLAIN ANALYZE to confirm full table scan and estimate time saved.- Example: find predicate columns and cardinality; check whether an index can be selective.4. Prioritize index creation- Rank by expected benefit = frequency * (current_time - estimated_index_time). Practically: - High frequency + high latency first. - Queries touching very large tables next. - High business impact queries (dashboards, SLAs) prioritized even if less frequent. - Favor indexes with low write overhead (on tables with fewer writes). - Prefer covering indexes that satisfy SELECT columns to avoid lookups.5. Validate and monitor- Create index on staging or with CONCURRENTLY (Postgres) for production safety: sql
CREATE INDEX CONCURRENTLY ON schema.table (col1, col2);
- Re-run pg_stat_statements and EXPLAIN ANALYZE; measure reductions in total_time, seq_scan, CPU, and dashboard latency.- Rollback if write performance regressions occur or benefits are marginal.Key trade-offs: index improves reads but costs writes and storage. Use selective columns, composite indexes in query order, and consider partial or expression indexes for sparsity.