在 Oracle 資料庫管理中,優化器是決定 SQL 執行效率的核心組件。本文將系統介紹 Oracle 優化器的兩種優化方式(RBO 與 CBO)、四種優化模式,並深入解析為何有索引卻不走索引的常見問題,幫助 DBA 與開發人員掌握執行計劃分析的核心技能。
RBO 遵循 Oracle 內部預定的固定規則集。例如:WHERE 子句中有索引列時優先走索引、等值連接優於範圍掃描等。RBO 不考慮數據分佈、表大小等統計信息,僅依靠規則優先級判斷執行路徑。Oracle 10g 後已不再推薦使用 RBO。
CBO 是 Oracle 8i 及後續版本的主流優化模式。它根據表、索引、列的統計信息(行數、區塊數、異值個數、直方圖等),計算各可能執行計劃的「成本」(CPU、I/O、內存消耗),選擇成本最低者。統計信息由 ANALYZE 或 DBMS_STATS 收集,若統計信息過期或缺失,CBO 可能產生錯誤計劃。
關鍵觀念:不一定走索引才是最優。例如一張僅有兩行數據的小表,全表掃描只需 1 次 I/O,而走索引需 2 次 I/O(索引塊 + 表塊),此時 Full Table Scan 反而更優。
| 模式 | 觸發條件 | 行為特徵 | 適用場景 |
|---|---|---|---|
| RULE | 強制指定 | 純 RBO,忽略統計信息 | 舊系統相容、無統計信息環境 |
| CHOOSE | 預設模式 | 有統計信息→CBO;無統計且有索引→RBO;其它→全表掃描 | 混合環境過渡期 |
| FIRST_ROWS | 指定或 Hint | 有統計信息→CBO 優化「首幾行響應時間」;無統計→RBO | OLTP、分頁查詢、Web 應用 |
| ALL_ROWS | 指定或 Hint | 有統計信息→CBO 優化「整體吞吐量」;無統計→RBO | 數據倉庫、批量報表、ETL |
修改 init 或 spfile:
OPTIMIZER_MODE = ALL_ROWS -- 或 FIRST_ROWS, CHOOSE, RULE
未設定時預設為 CHOOSE。
ALTER SESSION SET OPTIMIZER_MODE = FIRST_ROWS;
使用 Hint 強制指定:
SELECT /*+ FIRST_ROWS */ col1, col2 FROM tbl WHERE id = :b1;
DBMS_STATS.GATHER_TABLE_STATS(推薦)或 ANALYZE TABLE ... COMPUTE STATISTICS。/*+ INDEX(tbl idx_name) */。SELECT table_name, num_rows, last_analyzed FROM user_tables WHERE table_name = 'YOUR_TABLE';
SELECT index_name, num_rows, last_analyzed FROM user_indexes WHERE table_name = 'YOUR_TABLE';
EXEC DBMS_STATS.GATHER_TABLE_STATS(ownname => 'SCOTT', tabname => 'EMP', cascade => TRUE);
EXEC DBMS_STATS.GATHER_INDEX_STATS(ownname => 'SCOTT', indname => 'PK_EMP');