三種優化器模式
| 模式 | 參數值 | 特點 | 適用性 |
| RULE (RBO) | OPTIMIZER_MODE=RULE | 固定規則、不看統計、已棄用 | 不建議使用 |
| COST (CBO) | OPTIMIZER_MODE=ALL_ROWS / FIRST_ROWS_n | 成本模型、依統計資訊、預設 | 所有生產環境 |
| CHOOSE | OPTIMIZER_MODE=CHOOSE | 有統計用 CBO、無統計用 RBO | 不建議 (行為不可預期) |
CBO 核心依賴:統計資訊
必收集統計項目
- 表:行數、區塊數、平均行長
- 欄位:NDV (非重複值數)、NULL 數、密度、直方圖
- 索引:層級、葉區塊、叢集因子、非重複鍵值
- 系統:CPU 速度、I/O 吞吐 (DBMS_STATS.GATHER_SYSTEM_STATS)
收集指令
-- 基本收集
EXEC DBMS_STATS.GATHER_TABLE_STATS('SCOTT', 'EMP', CASCADE => TRUE);
-- 生產環境建議參數
EXEC DBMS_STATS.GATHER_TABLE_STATS(
ownname => 'SCOTT', tabname => 'EMP',
estimate_percent => DBMS_STATS.AUTO_SAMPLE_SIZE,
method_opt => 'FOR ALL COLUMNS SIZE AUTO',
cascade => TRUE, degree => 4, granularity => 'AUTO');
-- 系統統計 (關鍵!)
EXEC DBMS_STATS.GATHER_SYSTEM_STATS('INTERVAL', 60); -- 工作負載模式
-- 或
EXEC DBMS_STATS.GATHER_SYSTEM_STATS('NOWORKLOAD'); -- 模擬模式
Bind Variable 與游標共享
硬解析 vs 軟解析
- Hard Parse:Library Cache Miss → 語法/語義檢查 → 優化 → 存入 Cache
- Soft Parse:Library Cache Hit → 直接執行
CURSOR_SHARING 參數
| 值 | 行為 | 風險 |
| EXACT (預設) | 完全匹配 (含字面值) | 字面值 SQL 導致 Hard Parse 暴增 |
| FORCE | 強制替換字面值為 Bind Variable | 可能產生次優計畫、直方圖失效 |
| SIMILAR (11g 棄用) | 類似 FORCE 但保留直方圖 | 同上 |
最佳實踐:應用層使用 Bind Variable,資料庫保持 EXACT。
SQL Plan Management (SPM) - 11g+ 計畫穩定
運作流程
- Capture:自動/手動載入計畫至 SQL Plan Baseline
- Select:優化器僅選擇 Accepted 的計畫
- Evolve:新計畫驗證通過後標記 Accepted
關鍵操作
-- 啟用自動捕獲
ALTER SYSTEM SET OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES = TRUE;
-- 手動載入 (從 Cursor Cache)
DECLARE
n PLS_INTEGER;
BEGIN
n := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(
sql_id => 'abc123', fixed => 'YES');
END;
/
-- 查詢 Baseline
SELECT sql_handle, plan_name, enabled, accepted, fixed, origin
FROM dba_sql_plan_baselines;
-- 演進驗證
SET SERVEROUTPUT ON
DECLARE
rpt CLOB;
BEGIN
rpt := DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE(
sql_handle => 'SYS_SQL_123', verify => 'YES', commit => 'YES');
DBMS_OUTPUT.PUT_LINE(rpt);
END;
/
-- 固定計畫 (不再演進)
EXEC DBMS_SPM.ALTER_SQL_PLAN_BASELINE(plan_name => 'PLAN_1', attribute_name => 'FIXED', attribute_value => 'YES');
存取路徑選擇原則
| 路徑 | 觸發條件 | Hint 強制 |
| Full Table Scan | 無索引、低選擇性 (>5-10%)、小表、平行查詢 | FULL(t) |
| Index Range Scan | 高選擇性、前導欄位有範圍條件 | INDEX(t idx_name) |
| Index Unique Scan | 唯一索引、等值條件含所有鍵欄位 | INDEX(t idx_name) |
| Index Fast Full Scan | 需所有索引欄位、無排序需求 | INDEX_FFS(t idx_name) |
| Index Skip Scan | 複合索引前導欄位低基數、後續欄位高選擇性 | INDEX_SS(t idx_name) |
| Full Index Scan | 索引含所有查詢欄位、需排序 | INDEX(t idx_name) |
常見計畫錯誤排查步驟
- 確認統計資訊新鮮度:
SELECT last_analyzed FROM dba_tables WHERE table_name='...'
- 檢查直方圖:
SELECT column_name, histogram FROM dba_tab_col_statistics WHERE table_name='...'
- 查看實際執行計畫:
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(sql_id, child_number, 'ALL'))
- 比較估算 vs 實際行數 (E-Rows vs A-Rows)
- 若估算嚴重偏差 → 收集直方圖、延伸統計、動態採樣
- 若仍錯誤 → SQL Profile / SPM Baseline / Hint (最後手段)
- 上一篇文章: 從 MySQL 遷移至 Oracle 完整指南:SQL Developer Migration、資料類型對照、函數轉換與效能驗證
- 下一篇文章: Oracle 資料庫徹底移除指南:服務、註冊表、檔案系統、環境變數零殘留清單
Copyright ©
程式碼之家 All Rights Reserved