目錄html
當optimizer_capture_sql_plan_baselines參數設置爲TRUE,查詢優化器自動存儲新SQL計劃的基線,默認是FALSE。sql
第一個SQL語句被執行只是把signature插入到log日誌中,第二次相同的語句執行時,一個SQL執行基線僅包含建立當前執行計劃並標記被接受。第三次執行相同的語句時,基線的中執行計劃和當前的執行計劃作比較,若是不匹配,根據當前的查詢優化器作評估,爲了保存這些信息,會把當前的執行計劃寫入sql基線中並標記不接受。ide
當先的執行計劃被存儲到SQL執行基線中,如下兩種狀況很重要作區分優化
爲了手工加載SQL執行基線加載到數據字典中基於在libarary cache中游標存儲,這個dbms_spm包中的load_plans_from_cursor_cache是可用的。ui
能夠把執行計劃中原本是全表掃描的,不更改任何的SQL語句,使它走索引的模式。spa
ALTER SESSION SET optimizer_capture_sql_plan_baselines = TRUE; SELECT /*+ full(t) */ * FROM employees where employee_id>110; ALTER SESSION SET optimizer_capture_sql_plan_baselines = FALSE;
從新運行語句日誌
SELECT /*+ full(t) */ * FROM employees where employee_id>110;
查看執行計劃code
select * from table(dbms_xplan.display_cursor(null,null)); SQL_ID b2j5kmkx67r6t, child number 3 ------------------------------------- SELECT /*+ full(t) */ * FROM employees where employee_id>110 Plan hash value: 603312277 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 4 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 97 | 6693 | 4 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 97 | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPLOYEE_ID">110) Note ----- - SQL plan baseline SQL_PLAN_6bu51x6d0cb5215f09a65
經過執行計劃中NOTE信息獲取sql_handleorm
SELECT sql_handle FROM dba_sql_plan_baselines WHERE plan_name ='SQL_PLAN_6bu51x6d0cb5215f09a65';
再使語句走INDEX的模式,手工構造HINTS模式htm
select /*+index(employees emp_emp_id_pk)*/ * from employees where employee_id>110; select * from table(dbms_xplan.display_cursor(null,null)); SQL_ID 0gd91j77ppkc7, child number 0 ------------------------------------- select /*+index(employees emp_emp_id_pk)*/ * from employees where employee_id>110 Plan hash value: 603312277 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 4 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 97 | 6693 | 4 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 97 | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPLOYEE_ID">110)
你替換使用在sql基線中的執行計劃,加載的執行計劃關聯索引的,移除所有掃描
declare ret number(20); begin ret := dbms_spm.load_plans_from_cursor_cache(sql_handle => 'SQL_65e8a1e99a062ca2', sql_id => '0gd91j77ppkc7', plan_hash_value => '603312277'); end; declare ret number(20); begin ret :=dbms_spm.drop_sql_plan_baseline(sql_handle => 'SQL_65e8a1e99a062ca2', plan_name => 'SQL_PLAN_6bu51x6d0cb52cf314e9e'); end;
再次執行SQL語句
SELECT /*+ full(t) */ * FROM employees where employee_id>110; select * from table(dbms_xplan.display_cursor(null,null)); SQL_ID b2j5kmkx67r6t, child number 3 ------------------------------------- SELECT /*+ full(t) */ * FROM employees where employee_id>110 Plan hash value: 603312277 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 4 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| EMPLOYEES | 97 | 6693 | 4 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | EMP_EMP_ID_PK | 97 | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPLOYEE_ID">110) Note ----- - SQL plan baseline SQL_PLAN_6bu51x6d0cb5215f09a65
全表掃描的SQL語句已經替換爲index的模式來處理,爲了確認是否使用了SQL基線,你能夠覈對V$SQL中的SQL_PLAN_BASELINE字段
ret := dbms_spm.load_plans_from_sqlset(sqlset_name => 'test_sqlset', sqlset_owner => user);