oracle 9i,10g,11g執行計劃的固定一直是oracle的心病之一,雖然CBO很強了,在10g裏咱們用outline,引入sql_profile,11g裏用sql_profile,引入sql_plan_baseline
1 相關參數
optimizer_capture_sql_plan_baselines默認值false,即不採用自動捕獲
optimizer_use_sql_plan_baselines 默認值true,即優先使用dba_sql_plan_baselines裏的執行計劃;
2 默認參數測試
有條SQL很簡單:select * from hr.emp where EMPLOYEE_ID=206;
此表無索引,無主鍵,就是一個最普通的堆表
執行計劃無懸念:全表掃苗:sql
SQL> select* from table(dbms_xplan.display_cursor('76rrg3a06j24n',0)); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------- SQL_ID 76rrg3a06j24n, child number 0 ------------------------------------- select * from hr.emp where EMPLOYEE_ID=206 Plan hash value: 3956160932 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 2 (100)| | |* 1 | TABLE ACCESS FULL| EMP | 1 | 133 | 2 (0)| 00:00:01 | --------------------------------------------------------------------------
創建基線:oracle
declare v_ret varchar2(100); begin v_ret := dbms_spm.load_plans_from_cursor_cache(sql_id=>'76rrg3a06j24n'); end;
檢查基線:ide
select sql_handle,sql_text,origin,version,enabled,accepted,fixed from dba_sql_plan_baselines SQL_HANDLE SQL_TEXT ORIGIN VERSION ENABLED ACCEPTED FIXED SQL_4313a2ffff308f08 <CLOB> MANUAL-LOAD 11.2.0.4.0 YES YES NO
創建索引:create index i_employee_id on hr.emp(employee_Id);
再次執行,檢查child_number:測試
select sql_id,child_number,sql_text ,child_Number from v$sql where sql_text like 'select %hr.emp%'; SQL_ID CHILD_NUMBER SQL_TEXT CHILD_NUMBER 76rrg3a06j24n 1 select * from hr.emp where EMPLOYEE_ID=206 1
查看其執行計劃:this
Plan hash value: 3956160932 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 2 | 266 | 2 (0)| 00:00:01 | |* 1 | TABLE ACCESS FULL| EMP | 2 | 266 | 2 (0)| 00:00:01 | -------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("EMPLOYEE_ID"=206) Note ----- - SQL plan baseline "SQL_PLAN_464x2zzzm13s8d8a279cc" used for this statement
依舊全表掃描,這是不科學的,理論上是走索引,他給出了說明,走的是SQL_PLAN_464x2zzzm13s8d8a279cc,檢查dba_sql_plan_baselinescode
SQL_HANDLE SQL_TEXT ORIGIN VERSION ENABLED ACCEPTED FIXED PLAN_NAME SQL_4313a2ffff308f08 <CLOB> MANUAL-LOAD 11.2.0.4.0 YES YES NO SQL_PLAN_464x2zzzm13s8d8a279cc SQL_4313a2ffff308f08 <CLOB> AUTO-CAPTURE 11.2.0.4.0 YES NO NO SQL_PLAN_464x2zzzm13s8f5e7e8ee
這裏其實他是捕捉到另外一個執行計劃了,可是,因爲沒啓用,就是全表掃描了,啓用新的執行計劃:orm
declare tp clob; begin tp:=dbms_spm.evolve_sql_plan_baseline(sql_handle=>'SQL_4313a2ffff308f08',plan_name=>'SQL_PLAN_464x2zzzm13s8f5e7e8ee'); end;
再次運行:索引
Plan hash value: 1162342648 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 133 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 133 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | I_EMPLOYEE_ID | 1 | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPLOYEE_ID"=206) Note ----- - dynamic sampling used for this statement (level=2) - SQL plan baseline "SQL_PLAN_464x2zzzm13s8f5e7e8ee" used for this statement
好了,走正常的執行計劃了,再次刪除較優的base_line:hash
declare v_ret varchar2(100); begin v_ret:= dbms_spm.drop_sql_plan_baseline(sql_handle=>'SQL_4313a2ffff308f08',plan_name=>'SQL_PLAN_464x2zzzm13s8f5e7e8ee'); end ;
毫無疑問,又走全表掃描了,但dba_hist_sql_plan_baselines裏依舊是生成了的,只是沒有啓用而已;
修改狀態:it
declare v_ret varchar2(100); begin v_ret := dbms_spm.alter_sql_plan_baseline( sql_handle=>'SQL_4313a2ffff308f08', plan_name=>'SQL_PLAN_464x2zzzm13s8d8a279cc', attribute_name=>'enabled', attribute_value=>'NO' ); end;
查看執行計劃,兩個都沒啓用了,這和修改參數(optimizer_use_sql_plan_baselines=false)是同樣的:
Execution Plan
---------------------------------------------------------- Plan hash value: 1162342648 --------------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | --------------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 133 | 2 (0)| 00:00:01 | | 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 133 | 2 (0)| 00:00:01 | |* 2 | INDEX RANGE SCAN | I_EMPLOYEE_ID | 1 | | 1 (0)| 00:00:01 | --------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("EMPLOYEE_ID"=206) Note ----- - dynamic sampling used for this statement (level=2)