鐵律一:天下沒有免費的午餐 — 索引有代價
- **建立/維護成本**:每次 INSERT/UPDATE/DELETE 需同步更新所有索引 B-tree。
- **空間佔用**:每個索引佔用額外磁碟 (非叢集索引含書籤/RowLocator)。
- **統計維護**:自動/手動更新統計資料消耗 CPU/IO。
- **決策**:只有當查詢效能提升 **明顯大於** 寫入/空間/維護成本時,才建立索引。
鐵律二:低選擇性、低頻查詢欄位 — 不建索引
- **性別、狀態碼、布林旗標** (重複值極高,選擇性 < 1%):掃描表通常比 Index Seek + Key Lookup 更快。
- **從未出現在 WHERE/JOIN/ORDER BY/GROUP BY** 的欄位:純浪費。
- **例外**:作為覆蓋索引 `INCLUDE` 欄位、或外鍵欄位 (需索引避免鎖升級/死鎖)。
鐵律三:範圍查詢、排序、分組欄位 — 優先考慮叢集索引
- `BETWEEN`、`>`, `<`, `>=`, `<=`、`ORDER BY`、`GROUP BY` 欄位:資料物理連續,範圍掃描極快。
- **避免**單調遞增鍵 (`IDENTITY`, `datetime` 預設值) 做叢集鍵 → 熱點頁鎖爭用。改用 `NEWSEQUENTIALID()` 或雜湊分散鍵。
- **避免**頻繁更新的欄位做叢集鍵 → 資料列物理移動產生轉發指標/分頁分裂。
鐵律四:複合索引前導欄必須是核心查詢的高選擇性欄位
- 索引 `(A,B,C)`:查詢 `WHERE B=1` **無法 Seek** (除非 `A` 也在條件中)。
- 前導欄選擇依據:**查詢頻率 × 選擇性** 乘積最大者優先。
- **覆蓋索引**:將 `SELECT` 清單欄位加入 `INCLUDE`,消除 Key Lookup。
鐵律五:定期重建/重組索引與更新統計資料
| 碎片程度 | 動作 | 線上/離線 |
| 5% - 30% | ALTER INDEX REORGANIZE (線上、單執行緒、不更新統計) | 線上 |
| > 30% | ALTER INDEX REBUILD (可 ONLINE=ON、多執行緒、自動更新統計) | 線上 (Enterprise) / 離線 |
- **統計資料**:大表啟用 `AUTO_UPDATE_STATISTICS_ASYNC` 避免查詢等待;排程 `UPDATE STATISTICS WITH FULLSCAN` 或 `PERSIST_SAMPLE_PERCENT` 於維護窗口。
- **重建後**務必 `UPDATE STATISTICS` (REBUILD 已含) 並清除相關計畫快取 (`DBCC FREEPROCCACHE` 或 `sp_recompile`)。
鐵律六:監控與審計 — 沒有測量就沒有優化
- `sys.dm_db_index_usage_stats`:找出**從未被 Seek/Scan/Lookup** 的索引 → 刪除候選。
- `sys.dm_db_missing_index_details`:優化器建議的缺失索引 → 評估後建立。
- `sys.dm_db_index_physical_stats`:碎片率、頁面密度、轉發記錄計數。
- **命名慣例**:`IX_Table_Col1_Col2_Incl_Col3` 一目了然。
實務檢查清單 (每季執行)
- 匯出 `index_usage_stats`,標記 `user_seeks=user_scans=user_lookups=0` 且存在 > 90 天的索引 → 評估刪除。
- 匯出 `missing_index`,計算 `avg_total_user_cost * avg_user_impact * (user_seeks+user_scans)` 前 20 名 → 評估建立。
- 檢查碎片 > 30% 的索引 → 排程 REBUILD。
- 檢查統計資料最後更新時間 > 7 天且資料變動 > 20% → 更新統計。
- 檢查 `INCLUDE` 欄位是否過多 (索引寬度 > 900 bytes) → 拆分或改用檢視表/計算欄位。
結語
索引管理不是一次性動作,而是**持續監控 → 量化評估 → 精準調整**的閉環。遵循六大鐵律,建立自動化巡檢腳本 (PowerShell/dbatools),讓索引真正成為效能加速器而非負擔。