索引能加速查詢,但每筆 INSERT/UPDATE/DELETE 都需同步維護索引。若索引長期「user_updates 極大、但 user_seeks/scans/lookups 接近 0」,代表它白白消耗寫入效能卻未曾被查詢使用,應優先評估移除。
SELECT TOP 1000
o.name AS 表名,
i.name AS 索引名,
i.index_id AS 索引ID,
dm_ius.user_seeks AS 搜尋次數,
dm_ius.user_scans AS 掃描次數,
dm_ius.user_lookups AS 書籤查找次數,
dm_ius.user_updates AS 更新次數,
p.TableRows AS 表行數,
'DROP INDEX ' + QUOTENAME(i.name)
+ ' ON ' + QUOTENAME(s.name) + '.' + QUOTENAME(OBJECT_NAME(dm_ius.OBJECT_ID)) AS 刪除語句
FROM sys.dm_db_index_usage_stats dm_ius
INNER JOIN sys.indexes i
ON i.index_id = dm_ius.index_id
AND dm_ius.OBJECT_ID = i.OBJECT_ID
INNER JOIN sys.objects o
ON dm_ius.OBJECT_ID = o.OBJECT_ID
INNER JOIN sys.schemas s
ON o.schema_id = s.schema_id
INNER JOIN (
SELECT SUM(p.rows) AS TableRows, p.index_id, p.OBJECT_ID
FROM sys.partitions p
GROUP BY p.index_id, p.OBJECT_ID
) p
ON p.index_id = dm_ius.index_id
AND dm_ius.OBJECT_ID = p.OBJECT_ID
WHERE OBJECTPROPERTY(dm_ius.OBJECT_ID, 'IsUserTable') = 1
AND dm_ius.database_id = DB_ID()
AND i.type_desc = 'nonclustered'
AND i.is_primary_key = 0
AND i.is_unique_constraint = 0
AND o.name = 'tblorders' -- 請依實際需求修改或移除此行
ORDER BY (dm_ius.user_seeks + dm_ius.user_scans + dm_ius.user_lookups) ASC;
| 指標組合 | 含義 | 建議動作 |
|---|---|---|
| user_updates 高、seeks/scans/lookups = 0 | 純寫入負擔,零查詢效益 | 強力候選刪除 |
| user_updates 高、seeks/scans/lookups 低 | 維護成本遠大於查詢收益 | 評估查詢模式,確認可移除 |
| 所有計數皆低 | 冷資料表或新建索引未被使用 | 觀察一段時間再決定 |
sys.dm_db_index_usage_stats 隨 SQL Server 服務重啟歸零,務必在「代表性工作負載運行足夠長時間」後再跑此腳本。sys.dm_exec_query_stats 交叉驗證。CASCADE DELETE/UPDATE 效能至關重要,刪除前請確認無 FK 依賴。將此腳本加入每日/每週維護作業,輸出至資料表並配合郵件通知,長期追蹤索引使用趨勢,做數據驅動的索引精簡決策。