索引是雙面刃:
原則:查詢效能收益 > 維護成本 時才建索引。
SQL Server 自動建立/更新統計資料(直方圖 + 密度向量)。優化器依統計資料估算列數:
-- 查看統計資料
DBCC SHOW_STATISTICS ('TableName', 'IndexName')
-- 手動更新
UPDATE STATISTICS TableName IndexName WITH FULLSCAN
CREATE INDEX IX_Orders_CustDate ON Orders (CustomerID, OrderDate)
-- 可用:WHERE CustomerID = 1
-- 可用:WHERE CustomerID = 1 AND OrderDate > '2024-01-01'
-- 不用:WHERE OrderDate > '2024-01-01' -- 缺少前導欄位
基數:A 欄 30% 重複、B 欄 10% 重複、C 欄 25% 重複 → 順序 B, C, A。
例外:查詢模式固定為 WHERE A = ? AND B = ? → 依查詢順序調整。
INT 4 位元組、BIGINT 8、DATETIME 8、CHAR(n) n、VARCHAR(n) n+2CREATE INDEX IX_Orders_Cover ON Orders (CustomerID, OrderDate)
INCLUDE (Amount, Status)
-- 查詢 SELECT Amount, Status FROM Orders WHERE CustomerID=1 AND OrderDate>...
-- 純索引掃描,無 Key Lookup
| 場景 | Fill Factor | 理由 |
|---|---|---|
| 唯讀/極少寫入 | 100 (預設) | 最大密度,最小空間 |
| 隨機鍵值頻繁插入 (GUID、Identity 非遞增) | 70-80% | 預留空間容納新列,減少頁分裂 |
| 遞增鍵值 (Identity、DateTime) | 100% | 永遠附加在尾頁,不分裂 |
| 大量更新導致列長度變化 | 80-90% | 預留更新空間 |
CREATE INDEX IX_Orders_Random ON Orders (RandomGUID) WITH (FILLFACTOR = 80)
ALTER INDEX IX_Orders_Random ON Orders REBUILD WITH (FILLFACTOR = 80)
-- Ola Hallengren 索引優化腳本核心邏輯
-- 頁面碎片 > 30% → REBUILD (ONLINE=ON)
-- 頁面碎片 5-30% → REORGANIZE
-- 頁面計數 < 1000 → 跳過
-- 統計資料更新:修改列數 > 20% + 500 → UPDATE STATISTICS WITH FULLSCAN
-- 未使用索引 (自上次重啟)
SELECT OBJECT_NAME(i.object_id) AS TableName, i.name AS IndexName
FROM sys.indexes i
JOIN sys.objects o ON i.object_id = o.object_id
LEFT JOIN sys.dm_db_index_usage_stats s ON i.object_id = s.object_id AND i.index_id = s.index_id
WHERE o.type = 'U' AND i.type_desc = 'NONCLUSTERED'
AND (s.object_id IS NULL OR (s.user_seeks=0 AND s.user_scans=0 AND s.user_lookups=0))
-- 重複索引 (相同鍵欄位、相同包含欄位)
-- 需人工審視 sys.index_columns 對比
sys.dm_exec_query_stats、Query Store、Extended EventsPage Splits/sec、Index Fragmentation、Missing Index DMVs