「索引失效」實為:**優化器選擇全表掃描而非索引訪問**,或**索引存在但無法被正確使用**。分為「結構性失效」(索引不可用)與「選擇性失效」(CBO 判斷不划算)。
| # | 原因 | 錯誤示例 | 正確示例 | 原理 |
|---|---|---|---|---|
| 1 | 隱式類型轉換 | WHERE varchar_col = 123 | WHERE varchar_col = '123' | 數字轉字符導致列函數化,索引無法匹配 |
| 2 | 列上操作/函數 | WHERE id - 1 = 9WHERE ROUND(id) = 10 | WHERE id = 10CREATE INDEX fbi ON t(ROUND(id)) | 破壞索引列順序/值,需建函數索引 (FBI) |
| 3 | LIKE 通配符前置 | WHERE name LIKE '%abc' | WHERE name LIKE 'abc%' | B-Tree 索引需前綴匹配,前置 % 導致全掃描 |
| 4 | 復合索引非前導列單獨引用 | 索引 (a,b,c),查詢 WHERE b=1 | WHERE a=1 AND b=2 或建單列索引 | 索引樹按 (a,b,c) 排序,缺前導列無法定位 |
| 5 | 字符列存數字未加引號 | 同 #1,極高頻錯誤 | 同上 | 同 #1 |
| 6 | NOT IN / NOT EXISTS | WHERE id NOT IN (SELECT ...) | WHERE NOT EXISTS (SELECT 1 ...) 或 LEFT JOIN ... WHERE IS NULL | NULL 語義導致優化器放棄索引半連接 |
| 7 | 日期/時間類型不匹配 | 變量 TIMESTAMP vs 列 DATE | 統一類型或顯式 CAST | 隱式轉換導致列函數化 |
| # | 原因 | 表現 | 對策 |
|---|---|---|---|
| 8 | 統計信息缺失/過期 | CBO 誤估基數,選錯計劃 | DBMS_STATS.GATHER_TABLE_STATS 定時任務,增量統計 |
| 9 | 數據傾斜無直方圖 | 熱門值走全掃,冷門值走索引 | METHOD_OPT=>'FOR COLUMNS SIZE AUTO/SKEWONLY col' |
| 10 | 表太小/選擇率過高 | 返回行數 > 表行數 10%~15% | 全表掃描確實更快,接受或建議分區/叢集 |
| 11 | 索引本身損壞/標記 UNUSABLE | STATUS='UNUSABLE' | ALTER INDEX ... REBUILD / REBUILD ONLINE |
| 索引類型 | IS NULL | IS NOT NULL | 備註 |
|---|---|---|---|
| B-Tree | ❌ 不存 NULL(單列) | ✅ 走索引 | 復合索引全 NULL 不存,部分 NULL 存 |
| Bitmap | ✅ 存 NULL | ✅ 走索引 | 低基數列首選,OLAP 環境 |
(a,b,c):WHERE a IS NULL → ❌ 不走(單列 NULL 不入 B-Tree)。WHERE a=1 AND b IS NULL → ✅ 走(前導列有值,後續列 NULL 存入索引)。WHERE a IS NULL AND b IS NULL → ❌ 不走(前導列 NULL)。WHERE a=1 AND b=2 AND c IS NULL → ✅ 走。CBO 計算公式簡化:
Index Cost ≈ BLEVEL + CEIL(Leaf_Blocks * Selectivity) + CEIL(Clustering_Factor * Selectivity)
FTS Cost ≈ Blocks / MBRC * MREADTIM / SREADTIM
**結論**:索引不僅要「存在」,更要「有序」(低 CF)。大量隨機插入的表需定期 ALTER INDEX REBUILD 或採用 INDEX ORGANIZED TABLE。
EXPLAIN PLAN / DBMS_XPLAN.DISPLAY_CURSOR:確認訪問路徑。10053 Trace:查看 CBO 內部成本計算細節。DBMS_STATS.REPORT_COL_USAGE:檢查列使用情況,指導統計收集。V$OBJECT_USAGE:監控索引實際使用情況(ALTER INDEX ... MONITORING USAGE)。索引失效多源於隱式轉換、列運算、統計失真、高選擇率、Clustering Factor 差;診斷看計劃、補統計、建 FBI、重構索引、調優 CF。