資料庫管理員最怕的情況:
傳統手段(OUTLINE、SQL PROFILE、HINT 強制)皆有侷限:維護困難、版本升級失效、無法自適應資料變化。
Oracle 11g 引入 SPM,提供 「驗證後才採用」 的演進機制:
| 元件 | 說明 | 關鍵視圖 |
|---|---|---|
| SQL Plan Baseline (SPB) | 已驗證接受的執行計畫集合 | DBA_SQL_PLAN_BASELINES |
| SQL Management Base (SMB) | SYSAUX 表空間內儲存 SPB、計畫歷史、日誌 | DBA_SQL_MANAGEMENT_CONFIG |
| 自動演進任務 | 維護視窗中自動執行 SPM Evolve | DBA_AUTOTASK_CLIENT |
方法 A:自動捕捉(參數控制)
ALTER SYSTEM SET optimizer_capture_sql_plan_baselines = TRUE SCOPE=BOTH;
風險:可能捕捉大量非核心 SQL,佔用 SYSAUX 空間。建議改用手動/載入方式。
方法 B:從 Cursor Cache 載入(推薦)
-- 載入特定 SQL_ID 的計畫
DECLARE
v_count PLS_INTEGER;
BEGIN
v_count := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(
sql_id => 'abc123def456',
fixed => 'NO' -- YES=固定不演進,NO=允許演進
);
DBMS_OUTPUT.PUT_LINE('Loaded ' || v_count || ' plans');
END;
/
方法 C:從 AWR/STS 載入(歷史優良計畫)
-- 從 AWR 載入
DECLARE
v_count PLS_INTEGER;
BEGIN
v_count := DBMS_SPM.LOAD_PLANS_FROM_AWR(
begin_snap => 1000,
end_snap => 1010,
basic_filter => 'sql_text LIKE ''%critical_table%'''
);
DBMS_OUTPUT.PUT_LINE('Loaded ' || v_count || ' plans');
END;
/
方法 D:從 SQL Tuning Set (STS) 載入
-- 建立 STS 並載入
EXEC DBMS_SQLTUNE.CREATE_SQLSET('MY_STS');
-- ... 將 SQL 加入 STS ...
DECLARE
v_count PLS_INTEGER;
BEGIN
v_count := DBMS_SPM.LOAD_PLANS_FROM_SQLSET(
sqlset_name => 'MY_STS',
basic_filter => 'parsing_schema_name = ''SCOTT'''
);
END;
/
-- 查看所有 Baseline
SELECT sql_handle, plan_name, enabled, accepted, fixed, reproduced,
elapsed_time/1e6 AS avg_elapsed_sec, executions
FROM dba_sql_plan_baselines
ORDER BY last_modified DESC;
-- 查看特定 SQL 的計畫細節
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE(
sql_handle => 'SYS_SQL_abc123', format => 'ADVANCED'));
手動觸發演進:
SET SERVEROUTPUT ON
DECLARE
v_report CLOB;
BEGIN
v_report := DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE(
sql_handle => 'SYS_SQL_abc123',
time_limit => 300, -- 秒
verify => 'YES' -- YES=執行比較,NO=僅檢查可行性
);
DBMS_OUTPUT.PUT_LINE(v_report);
END;
/
自動演進**:維護視窗(預設每天 22:00-06:00)自動執行 SYS_AUTO_SPM_EVOLVE_TASK。
-- 檢查自動任務狀態
SELECT client_name, status, window_group FROM dba_autotask_client
WHERE client_name = 'auto spatial optimizer'; -- 11g
-- 12c+ 改為
SELECT client_name, status FROM dba_autotask_client WHERE client_name LIKE '%spm%';
-- 固定計畫(不再演進,強制使用)
EXEC DBMS_SPM.ALTER_SQL_PLAN_BASELINE(
sql_handle => 'SYS_SQL_abc123',
plan_name => 'SYS_SQL_PLAN_xyz789',
attribute_name => 'FIXED', attribute_value => 'YES');
-- 停用計畫
EXEC DBMS_SPM.ALTER_SQL_PLAN_BASELINE(..., 'ENABLED', 'NO');
-- 移除計畫
EXEC DBMS_SPM.DROP_SQL_PLAN_BASELINE(
sql_handle => 'SYS_SQL_abc123', plan_name => 'SYS_SQL_PLAN_xyz789');
DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE 匯出 STSDBMS_SPM.LOAD_PLANS_FROM_SQLSET-- 變更參數前先建立 Baseline
EXEC DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(sql_id => 'critical_sql');
-- 變更參數
ALTER SYSTEM SET optimizer_index_cost_adj = 10 SCOPE=BOTH;
-- 觀察是否有新計畫產生並演進
SELECT sql_handle, plan_name, origin, created, last_verified
FROM dba_sql_plan_baselines WHERE sql_handle = 'SYS_SQL_...';
當資料傾斜改變(如州別分布從 NY 主導變為 CT 主導),優化器會產生新計畫(全表掃描取代索引)。SPM 會:
| 特性 | Outline (已棄用) | SQL Profile | SPM (11g+) |
|---|---|---|---|
| 版本支援 | 10g-11g | 10g+ | 11g+ |
| 自動演進 | 無 | 無 | 有 |
| 多計畫支援 | 單一 | 單一 | 多計畫(自適應) |
| 驗證機制 | 無 | 無 | 實際執行比較 |
| 持久性 | 遷移困難 | 遷移困難 | 原生支援匯入匯出 |
| Enterprise Manager 整合 | 無 | 有 | 完整整合 |
optimizer_capture_sql_plan_baselines = FALSE(避免雜訊)DBA_SQL_PLAN_BASELINES 中 REPRODUCED='NO' 的計畫(無法重現,需調查)FIXED='YES' 防止意外演進