Missing index suggestions (treat as hints)
SELECT TOP 20
DB_NAME(d.database_id) AS db, d.statement AS tbl,
d.equality_columns, d.inequality_columns, d.included_columns,
s.user_seeks, s.avg_user_impact,
s.user_seeks * s.avg_total_user_cost * s.avg_user_impact AS score
FROM sys.dm_db_missing_index_details d
JOIN sys.dm_db_missing_index_groups g ON g.index_handle = d.index_handle
JOIN sys.dm_db_missing_index_group_stats s ON s.group_handle = g.index_group_handle
WHERE d.database_id = DB_ID()
ORDER BY score DESC;
Before creating one:
- Check if an existing index can be extended instead (add a column or INCLUDE).
- Don't create every suggestion; they overlap and ignore write cost.
- Key column order: equality columns first, then the most selective inequality.
Unused indexes
SELECT OBJECT_NAME(i.object_id) AS tbl, i.name AS idx,
us.user_seeks, us.user_scans, us.user_lookups, us.user_updates
FROM sys.indexes i
LEFT JOIN sys.dm_db_index_usage_stats us
ON us.object_id = i.object_id AND us.index_id = i.index_id AND us.database_id = DB_ID()
WHERE OBJECTPROPERTY(i.object_id, 'IsUserTable') = 1
AND i.index_id > 1 AND i.is_primary_key = 0 AND i.is_unique_constraint = 0
AND ISNULL(us.user_seeks + us.user_scans + us.user_lookups, 0) = 0
ORDER BY us.user_updates DESC;
Usage stats reset on restart (and on some index operations). Check sqlserver_start_time in sys.dm_os_sys_info and make sure the period covers month-end and other cycles before dropping anything.
Duplicate and overlapping indexes
- Exact duplicates: same key columns in the same order. Drop one.
- Left-prefix overlap:
(A)and(A, B). The narrower one is often redundant unless it's unique or much smaller for a hot query. - Indexes differing only in INCLUDE columns can often be merged.
Safe change process
- Script the index definition before dropping (keep it in source control).
- Disable rather than drop first where practical:
ALTER INDEX ix ON t DISABLE;(not for clustered indexes). - Watch Query Store for regressed queries for a full business cycle.
- Drop when confident.
Measure the result
| Metric | Where |
|---|---|
| Top queries' duration and reads | Query Store |
| Write latency on hot tables | Query Store, wait stats |
| Database and backup size | Size trends |
| Buffer pool pressure | Page life expectancy trend |
Warning
Some indexes support rare but critical work (quarter-end reports, unique constraints, foreign key lookups during deletes). Ask application owners before removing indexes that look unused.
Checklist
- Missing index suggestions reviewed and consolidated
- Unused indexes identified over a full business cycle
- Duplicates and overlaps merged
- Definitions scripted; disable before drop
- Query Store checked after each change