Oracle 優化器會在開發者給出錯誤 Hint 時仍選擇正確執行計劃,這種「無私」特性體現了資料庫核心邏輯的健壯性。本文透過一個簡單實驗,展示 B-Tree 索引不存儲 NULL 值的特性,如何導致全表掃描而非索引掃描,以及加上 NOT NULL 約束後優化器如何果斷轉向索引快速全掃描,甚至允許 Hint 生效。
TBL_PLAN,欄位 ID NUMBERIDX_TBL_PLAN_ID ON TBL_PLAN(ID)SELECT ID FROM TBL_PLAN;
執行計劃: TABLE ACCESS FULL TBL_PLAN (全表掃描)
即使加上 Hint:
SELECT /*+ INDEX(TBL_PLAN IDX_TBL_PLAN_ID) */ ID FROM TBL_PLAN;
結果: 仍為全表掃描,Hint 被忽略。
B-Tree 索引不存儲完全為 NULL 的鍵值。 雖然表中實際無 NULL,但優化器僅根據中繼資料 (欄位定義允許 NULL) 判斷:若從索引讀取,可能遺漏 NULL 行,導致結果錯誤。為保證正確性,優化器拒絕使用索引,寧選全表掃描。
ALTER TABLE TBL_PLAN MODIFY (ID NOT NULL);
相當於將索引轉為「不含 NULL」的語義保證。
SELECT ID FROM TBL_PLAN;
執行計劃: INDEX FAST FULL SCAN IDX_TBL_PLAN_ID (索引快速全掃描) —— 最佳路徑!
SELECT /*+ INDEX(TBL_PLAN IDX_TBL_PLAN_ID) */ ID FROM TBL_PLAN;
結果: 此時 Hint 生效,執行計劃顯示 INDEX RANGE SCAN (或 INDEX FULL SCAN),優化器尊重開發者意圖。
| 場景 | 執行計劃 | Hint 效果 | 原因 |
|---|---|---|---|
| 可 NULL 欄位 + B-Tree 索引 | 全表掃描 | 忽略 | 索引可能遺漏 NULL 行,優化器保正確性 |
| NOT NULL 欄位 + B-Tree 索引 | 索引快速全掃描 | 生效 | 語義保證無 NULL,索引安全可用 |