以前寫了一篇博客介紹的是用SQL Profile來調整、穩定目標SQL的執行計劃,即便沒法修改目標SQL的SQL文本。但SQL Profile實際上只是一種亡羊補牢、被動的技術手段,應用在那些執行計劃已經發生了很差的變動的SQL上,即當咱們發現這些SQL的執行計劃已經出了問題時經過建立SQL Profile來糾正、穩定這些SQL的執行計劃。即使經過建立SQL Profile解決了目標SQL執行計劃變動的問題,依然不能保證系統後續執行的SQL的執行計劃就再也不發生很差的變動。這種不肯定性會給Oracle數據庫大版本升級(好比從Oracle 10g升級到Oracle 11g)帶來一系列的麻煩,由於不清楚升級以後原先系統中哪些SQL的執行計劃會發生很差的變動。算法
爲了解決上述問題,Oracle在11g中推出了SPM(SQL Plan Management)。SPM是一種主動的穩定執行計劃的手段,可以保證只有被驗證過的執行計劃纔會被啓用,當因爲種種緣由(如統計信息的變動)而致使目標SQL產生了新的執行計劃後,這個新的執行計劃並不會被立刻啓用,直到它已經被咱們驗證過其執行效率會比原先執行計劃高才會被啓用。sql
隨着Oracle數據庫版本的不段推動,其CBO的算法、功能也在一直不斷進化和增長,因此一樣的SQL有可能在新版本的Oralce數據庫中執行效率更高,若是咱們使用了SQL Profile(特別是使用了Manual類型的SQL Profile)來穩定目標SQL的執行計劃,那就意味着可能失去了繼續優化上述SQL的執行效率的機會。而SPM的推出能夠說完全解決了執行計劃穩定性的問題,它既能主動地穩定執行計劃,又保留了繼續使用新的執行效率可能更高的執行計劃的機會。數據庫
當啓用了SPM後,每個SQL都會存在對應的SQL Plan Baseline,這個SQL Plan Baseline裏存儲的就是該SQL的執行計劃,若是一個SQL有多個執行計劃,那麼該SQL就可能會有多個SQL Plan Baseline,能夠從DBA_SQL_PLAN_BASELINES中查看目標SQL全部的SQL Plan Baseline。session
DBA_SQL_PLAN_BASELINES中的列ENABLED和ACCEPTED用來描述一個SQL Plan Baseline所對應的執行計劃是否能被Oracle啓用,只有ENABLED和ACCEPTED的值均爲「YES」的SQL Plan Baseline所對應的執行計劃纔會被Oracle啓用,若是一具SQL有超過1個以上的SQL Plan Baseline的ENABLED和ACCEPTED的值均爲YES,則Oracle會從中選擇成本值最小的一個所對應的執行墳墓來做爲該SQL的執行計劃。ide
在Oracle 11g及其以上的版本中,有以下兩種方法能夠產生目標SQL的SQL Plan Baseline。測試
自動捕獲優化
手工生成/批量導入(批量導入尤爲適用於Oracle數據庫大版本的升級,它能夠確保升級後原有系統所胡SQL的執行計劃不會發生變化)this
下面分別介紹如何自動捕獲和手工的方式來產生SQL Plan Baseline。orm
1 自動捕獲SQL Plan Baselineblog
參數OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES用於控制是否開啓自動捕獲SQL Plan Baseline,其默認值爲FALSE,表示在默認狀況下,Oracle並不會自動捕獲SQL Plan Baseline。這個參數能夠在session或系統級別動態修改。當修改成TRUE後,則Oracle會對上述參數影響範圍內全部重複執行的SQL自動捕獲其SQL Plan Baseline,而且針對目標SQL第一次捕獲的SQL Plan Baseline的ENABLED和ACCEPTED的值均爲「YES」。隨後若是該SQL的執行計劃發生了變動,則再次捕獲到的SQL Plan Baseline的ENABLED的值依然爲YES,但ACCEPTED的值變爲了NO,這表示後續變動的執行計劃雖然被捕獲了,但Oracle不會將其做爲該SQL的執行計劃來執行,即此時Oracle會永遠沿用該SQL第一次被捕獲的SQL Plan Baseline所對應的執行計劃(除非後續作了手工調整)。
參數OPTIMIZER_USE_SQL_PLAN_BASELINES用於控制是否啓用SQL Plan Baseline,其默認值爲TRUE,表示在默認狀況下,Oracle在生成執行計劃時就會啓用SPM,使用已有的SQL Plan Baseline,這個參數也能夠在session或系統級別動態修改。
下面看一下實例:
查看上述兩個參數的默認值
zx@MYDB>show parameter sql_plan NAME TYPE VALUE ------------------------------------ --------------------------------- ------------------------------ optimizer_capture_sql_plan_baselines boolean FALSE optimizer_use_sql_plan_baselines boolean TRUE
在當前session中禁掉SPM並同時開啓自動捕獲SQL Plan Baseline:
zx@MYDB>alter session set optimizer_use_sql_plan_baselines=FALSE; Session altered. zx@MYDB>alter session set optimizer_capture_sql_plan_baselines=TRUE; Session altered.
建立測試表T2
zx@MYDB>create table t2 as select * from dba_objects; Table created. zx@MYDB>create index idx_t2 on t2(object_id); Index created. zx@MYDB>exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T2',estimate_percent=>100,cascade=>true); PL/SQL procedure successfully completed. zx@MYDB>select object_id,object_name from t2 where object_id between 103 and 108; OBJECT_ID OBJECT_NAME ---------- ------------------------------ 103 MIGRATE$ 104 DEPENDENCY$ 105 ACCESS$ 106 I_DEPENDENCY1 107 I_DEPENDENCY2 108 I_ACCESS1 6 rows selected.
從執行計劃上看,走的是索引IDX_T2上的索引範圍掃描,由於SQL只執行了一次,因此Oracle不會自動捕獲SQL Plan Baseline,DBA_SQL_PLAN_BASELINES中沒有記錄
zx@MYDB>col sql_handle for a30 zx@MYDB>col plan_name for a30 zx@MYDB>col origin for a20 zx@MYDB>col sql_text for a70 zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines; no rows selected
再次執行上述SQL,由於重複執行該SQL,Oracle自動捕獲了這個SQL的SQL Plan Baseline
zx@MYDB>select object_id,object_name from t2 where object_id between 103 and 108; OBJECT_ID OBJECT_NAME ---------- ------------------------------ 103 MIGRATE$ 104 DEPENDENCY$ 105 ACCESS$ 106 I_DEPENDENCY1 107 I_DEPENDENCY2 108 I_ACCESS1 6 rows selected. zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines; SQL_HANDLE PLAN_NAME ORIGIN ENABLED ACCEPTED SQL_TEXT ------------------------------ ------------------------------ -------------------- --------- --------- ------------------------------------------------------------ SYS_SQL_ac526b1e4be74880 SQL_PLAN_asnmb3t5yfk4024c6dbb6 AUTO-CAPTURE YES YES select object_id,object_name from t2 where object_id between 103 and 108
如今將索引IDX_T2的聚簇因子修改成2400萬,目的是爲了能讓SQL的執行計劃變爲對錶T2的全表掃描(爲什麼修改聚簇因子,參考http://hbxztc.blog.51cto.com/1587495/1901258)。修改完後再執行上述SQL,並查看執行計劃:
zx@MYDB>exec dbms_stats.set_index_stats(ownname=>USER,indname=>'IDX_T2',clstfct=>24000000,no_invalidate=>false); PL/SQL procedure successfully completed. zx@MYDB>select index_name,clustering_factor from dba_indexes where index_name='IDX_T2'; INDEX_NAME CLUSTERING_FACTOR ------------------------------------------------------------------------------------------ ----------------- IDX_T2 24000000 zx@MYDB>select object_id,object_name from t2 where object_id between 103 and 108; OBJECT_ID OBJECT_NAME ---------- ------------------------------ 103 MIGRATE$ 104 DEPENDENCY$ 105 ACCESS$ 106 I_DEPENDENCY1 107 I_DEPENDENCY2 108 I_ACCESS1 6 rows selected.
從執行計劃中能夠看出該SQL的執行計劃已經變爲全表掃描。由於目標SQL已經重複執行且同時又產生了一個新的執行計劃,因此如今Oracle就會自動捕獲並建立這個新的執行計劃所對應的SQL Plan Baseline了。從以下查詢能夠看出Oracle對新的執行計劃產生了一個新的SQL Plan Baseline,其ENABLED的值依然爲YES,但ACCEPTED的值變爲了NO:
如今咱們對當前Session關閉自動捕獲SQL Plan Baseline並同時開啓SPM,如今索引IDX_T2的聚簇因子依然爲2400萬,再次執行目標SQL,並查看執行計劃:
zx@MYDB>alter session set optimizer_use_sql_plan_baselines=TRUE; Session altered. zx@MYDB>alter session set optimizer_capture_sql_plan_baselines=FALSE; Session altered. zx@MYDB>select index_name,clustering_factor from dba_indexes where index_name='IDX_T2'; INDEX_NAME CLUSTERING_FACTOR ------------------------------------------------------------------------------------------ ----------------- IDX_T2 24000000 zx@MYDB>select object_id,object_name from t2 where object_id between 103 and 108; OBJECT_ID OBJECT_NAME ---------- ------------------------------ 103 MIGRATE$ 104 DEPENDENCY$ 105 ACCESS$ 106 I_DEPENDENCY1 107 I_DEPENDENCY2 108 I_ACCESS1 6 rows selected.
從上面的顯示內容能夠看出,如今目標SQL的執行又從全表掃描恢復爲了索引範圍掃描,而且執行計劃中的Note部分有「SQL plan baseline SQL_PLAN_asnmb3t5yfk4024c6dbb6 used for this statement」內容,說明SPM開啓的狀況下,即使目標SQL產生了新的執行計劃,Oracle依然只會應用該SQL的ENABLED和ACCEPTED的值均爲YES的SQL Plan Baselline。
若是想啓用目標SQL新的執行計劃(即全表掃描),應該如何作呢?
針對不一樣的Oracle版本,會有不一樣的處理方法。好比這裏想啓用目標SQL的新的執行計劃,若是是11gR1的環境,則只須要將目標SQL所採用的名爲SQL_PLAN_asnmb3t5yfk4024c6dbb6的SQL Plan Baseline(即索引範圍掃描)的ACCEPTED的值設爲NO就能夠了。但對於11gR2環境,上述方法會報錯,由於在11gR2中,全部已經被ACCEPTED的SQL Plan Baseline的ACCEPTED的值將再也不可以被設爲NO:
zx@MYDB>var temp varchar2(1000); zx@MYDB>exec :temp := dbms_spm.alter_sql_plan_baseline(sql_handle=>'SYS_SQL_ac526b1e4be74880',plan_name=>'SQL_PLAN_asnmb3t5yfk4024c6dbb6',attribute_name=>'accepted',attribute_value=>'NO'); BEGIN :temp := dbms_spm.alter_sql_plan_baseline(sql_handle=>'SYS_SQL_ac526b1e4be74880',plan_name=>'SQL_PLAN_asnmb3t5yfk4024c6dbb6',attribute_name=>'accepted',attribute_value=>'NO'); END; * ERROR at line 1: ORA-38136: invalid attribute name ACCEPTED specified ORA-06512: at "SYS.DBMS_SPM", line 2469 ORA-06512: at line 1
在11gR2中,咱們能夠聯合使用DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE和DBMS_SPM.ALTER_SQL_PLAN_BASELINE達到啓用目標SQL新的執行計劃的目的。
先用DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE將新的執行計劃(全表掃描)所對應的SQL Plan Baseline的ACCEPTED值設爲「YES」:
zx@MYDB>exec :temp := dbms_spm.evolve_sql_plan_baseline(sql_handle=>'SYS_SQL_ac526b1e4be74880',plan_name=>'SQL_PLAN_asnmb3t5yfk40b860bcf2',verify=>'NO',commit=>'YES'); PL/SQL procedure successfully completed.
從上面顯示的內容看到以下信息:「Plan: SQL_PLAN_asnmb3t5yfk40b860bcf2----Plan was changed to an accepted plan.」,這代表已經將新的執行計劃(全表掃描)所對應的SQL Plan Baseline的ACCEPTED值設爲YES
從下面的查詢結果也能夠證實:
zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select object_id%'; SQL_HANDLE PLAN_NAME ORIGIN ENABLED ACCEPTED SQL_TEXT ------------------------------ ------------------------------ -------------------- --------- --------- ---------------------------------------------------------------------- SYS_SQL_ac526b1e4be74880 SQL_PLAN_asnmb3t5yfk4024c6dbb6 AUTO-CAPTURE YES YES select object_id,object_name from t2 where object_id between 103 and 108 SYS_SQL_ac526b1e4be74880 SQL_PLAN_asnmb3t5yfk40b860bcf2 AUTO-CAPTURE YES YES select object_id,object_name from t2 where object_id between 103 and 108
而後再使用DBMS_SPM.ALTER_SQL_PLAN_BASELINE將原先的執行計劃(索引範圍掃描)對應的SQL Plan Baseline的ENABLED的值設爲NO:
zx@MYDB>exec :temp := dbms_spm.alter_sql_plan_baseline(sql_handle=>'SYS_SQL_ac526b1e4be74880',plan_name=>'SQL_PLAN_asnmb3t5yfk4024c6dbb6',attribute_name=>'enabled',attribute_value=>'NO'); PL/SQL procedure successfully completed. zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select object_id%'; SQL_HANDLE PLAN_NAME ORIGIN ENABLED ACCEPTED SQL_TEXT ------------------------------ ------------------------------ -------------------- --------- --------- ---------------------------------------------------------------------- SYS_SQL_ac526b1e4be74880 SQL_PLAN_asnmb3t5yfk4024c6dbb6 AUTO-CAPTURE NO YES select object_id,object_name from t2 where object_id between 103 and 108 SYS_SQL_ac526b1e4be74880 SQL_PLAN_asnmb3t5yfk40b860bcf2 AUTO-CAPTURE YES YES select object_id,object_name from t2 where object_id between 103 and 108
再次執行目標SQL
zx@MYDB>select object_id,object_name from t2 where object_id between 103 and 108; OBJECT_ID OBJECT_NAME ---------- ------------------------------ 103 MIGRATE$ 104 DEPENDENCY$ 105 ACCESS$ 106 I_DEPENDENCY1 107 I_DEPENDENCY2 108 I_ACCESS1 6 rows selected.
從上述顯示能夠看出,如今SQL的執行計劃已經變爲了全表掃描,咱們要啓用新的執行計劃(全表掃描)的目的已經實現,Note部分也有了提示。
從上述測試結果能夠看出,實際上咱們能夠輕易地在目標SQL的多個執行計劃中切換,因此SPM確實是既可以主動地穩定執行計劃,又保留了繼續使用新的執行計劃的機會,而且咱們很容易就能啓用新的執行計劃。
下面介紹手工生成SQL Plan Baseline:
手工生成目標SQL的SQL Plan Baseline其實很是簡單,其核心就是調用DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE。這裏只討論針對單個SQL的SQL Plan Baseline的手工生成。
以前介紹過用Manual類型的SQL Profile能夠在不改變目標SQL的SQL文本的狀況下調整其執行計劃。實際上,用手工生成SQL Plan Baseline的方式也徹底能夠實現一樣的目的,甚至會比使用Manual類型的SQL Profile更加簡潔。
手工生成目標SQL的SQL Plan Baseline的具體步驟爲:
1)針對目標SQL使用DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE手工生成其初始執行計劃所對應的SQL Plan Baseline。此時,使用DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE傳入的參數以下所示:
dbms_spm.load_plans_from_cursor_cache(sql_id=>'原目標SQL的SQL_ID',plan_hash_value=>原目標SQL的PLAN HASH VALUE)
2)改寫原目標SQL的SQL文本,在其中加入合適的Hint,直到加入Hint後的所改寫的SQL能走出咱們想要的執行計劃,而後對改寫後的SQL使用DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE手工生成新的執行計劃所對應的SQL Plan Baseline。此時傳入的參數以下所示:
dbms_spm.load_plans_from_cursor_cache(sql_id=>'加入合適Hint後改寫SQL的SQL_ID',plan_hash_value=>加入合適Hint後改寫SQL的PLAN HASH VALUE,sql_handle=>'原目標SQL在步驟(1)中所產生的SQL Plan Baseline的sql_handle')
3)使用DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE刪除步驟(1)中手工生成的原目標SQL的初始執行計劃所對應的SQL Plan Baseline。此時傳入的參數以下所示:
dbms_spm.drop_sql_plan_baseline(sql_handle=>'原目標SQL在步驟(1)中所產生的SQL Plan Baseline的sql_handle',plan_name=>'原目標SQL在步驟(1)中所產生的SQL Plan Baseline的plan_name')
下面使用一個實例演示:
zx@MYDB>select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_id=4; OBJECT_NAME OBJECT_ID ------------------------------ ---------- TAB$ 4 zx@MYDB>select * from table(dbms_xplan.display_cursor(null,null,'advanced')); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID 0n5z3wmf8qpgn, child number 0 ------------------------------------- select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_id=4 Plan hash value: 1513984157 -------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 287 (100)| | |* 1 | TABLE ACCESS FULL| T2 | 1 | 30 | 287 (1)| 00:00:04 | -------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 / T2@SEL$1 Outline Data ------------- /*+ BEGIN_OUTLINE_DATA IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('11.2.0.1') DB_VERSION('11.2.0.1') ALL_ROWS OUTLINE_LEAF(@"SEL$1") FULL(@"SEL$1" "T2"@"SEL$1") END_OUTLINE_DATA */ Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter("OBJECT_ID"=4) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - "OBJECT_NAME"[VARCHAR2,128], "OBJECT_ID"[NUMBER,22] 43 rows selected. zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+ no_index(t2 idx_t2)%'; no rows selected zx@MYDB>var temp number zx@MYDB>exec :temp :=dbms_spm.load_plans_from_cursor_cache(sql_id=>'0n5z3wmf8qpgn',plan_hash_value=>1513984157); PL/SQL procedure successfully completed. zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+ no_index(t2 idx_t2)%'; SQL_HANDLE PLAN_NAME ORIGIN ENABLED ACCEPTED SQL_TEXT ------------------------------ ------------------------------ -------------------- --------- --------- ---------------------------------------------------------------------- SYS_SQL_75b06ae056223f5f SQL_PLAN_7bc3aw1b24guzb860bcf2 MANUAL-LOAD YES YES select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_i d=4
從上述顯示目標SQL初始執行計劃爲全表掃描,sql_id和plan hash value能夠從執行計劃中找到,因爲沒有啓用自動捕獲SQL Plan Baseline,一開始沒有查到目標SQL對應的SQL Plan Baseline,手工生成後,能夠查到全表掃描對應的SQL Plan Baseline。
改寫原目標SQL,加入Hint後從新執行:
zx@MYDB>select /*+ index(t2 idx_t2) */ object_name,object_id from t2 where object_id=4; OBJECT_NAME OBJECT_ID ------------------------------ ---------- TAB$ 4 zx@MYDB>select * from table(dbms_xplan.display_cursor(null,null,'advanced')); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID 60txg87j30pvw, child number 0 ------------------------------------- select /*+ index(t2 idx_t2) */ object_name,object_id from t2 where object_id=4 Plan hash value: 2008370210 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 335 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 30 | 335 (0)| 00:00:05 | |* 2 | INDEX RANGE SCAN | IDX_T2 | 1 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 / T2@SEL$1 2 - SEL$1 / T2@SEL$1 Outline Data ------------- /*+ BEGIN_OUTLINE_DATA IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('11.2.0.1') DB_VERSION('11.2.0.1') ALL_ROWS OUTLINE_LEAF(@"SEL$1") INDEX_RS_ASC(@"SEL$1" "T2"@"SEL$1" ("T2"."OBJECT_ID")) END_OUTLINE_DATA */ Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID"=4) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - "OBJECT_NAME"[VARCHAR2,128], "OBJECT_ID"[NUMBER,22] 2 - "T2".ROWID[ROWID,10], "OBJECT_ID"[NUMBER,22] 46 rows selected. zx@MYDB>exec :temp :=dbms_spm.load_plans_from_cursor_cache(sql_id=>'60txg87j30pvw',plan_hash_value=>2008370210,sql_handle=>'SYS_SQL_75b06ae056223f5f'); PL/SQL procedure successfully completed. zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+ no_index(t2 idx_t2)%'; SQL_HANDLE PLAN_NAME ORIGIN ENABLED ACCEPTED SQL_TEXT ------------------------------ ------------------------------ -------------------- --------- --------- ---------------------------------------------------------------------- SYS_SQL_75b06ae056223f5f SQL_PLAN_7bc3aw1b24guz24c6dbb6 MANUAL-LOAD YES YES select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_i d=4 SYS_SQL_75b06ae056223f5f SQL_PLAN_7bc3aw1b24guzb860bcf2 MANUAL-LOAD YES YES select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_i d=4
從上述輸出能夠看出把改寫過的SQL的新的執行計劃所對應的SQL Plan Baseline已經成功生成,並且全部手工生成的SQL Plan Baseline的ENABLED和ACCEPTED的值均爲YES,這是和自動捕獲的SQL Plan Baseline不同的地方。
Drop掉原執行計劃(全表掃描)所對應的SQL Plan Baseline:
zx@MYDB>exec :temp := dbms_spm.drop_sql_plan_baseline(sql_handle=>'SYS_SQL_75b06ae056223f5f',plan_name=>'SQL_PLAN_7bc3aw1b24guzb860bcf2'); PL/SQL procedure successfully completed. zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+ no_index(t2 idx_t2)%'; SQL_HANDLE PLAN_NAME ORIGIN ENABLED ACCEPTED SQL_TEXT ------------------------------ ------------------------------ -------------------- --------- --------- ---------------------------------------------------------------------- SYS_SQL_75b06ae056223f5f SQL_PLAN_7bc3aw1b24guz24c6dbb6 MANUAL-LOAD YES YES select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_i d=4
再次執行原目標SQL,並查看執行計劃
zx@MYDB>select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_id=4; OBJECT_NAME OBJECT_ID ------------------------------ ---------- TAB$ 4 zx@MYDB>select * from table(dbms_xplan.display_cursor(null,null,'advanced')); PLAN_TABLE_OUTPUT -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- SQL_ID 0n5z3wmf8qpgn, child number 2 ------------------------------------- select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_id=4 Plan hash value: 2008370210 -------------------------------------------------------------------------------------- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | -------------------------------------------------------------------------------------- | 0 | SELECT STATEMENT | | | | 335 (100)| | | 1 | TABLE ACCESS BY INDEX ROWID| T2 | 1 | 30 | 335 (0)| 00:00:05 | |* 2 | INDEX RANGE SCAN | IDX_T2 | 1 | | 1 (0)| 00:00:01 | -------------------------------------------------------------------------------------- Query Block Name / Object Alias (identified by operation id): ------------------------------------------------------------- 1 - SEL$1 / T2@SEL$1 2 - SEL$1 / T2@SEL$1 Outline Data ------------- /*+ BEGIN_OUTLINE_DATA IGNORE_OPTIM_EMBEDDED_HINTS OPTIMIZER_FEATURES_ENABLE('11.2.0.1') DB_VERSION('11.2.0.1') ALL_ROWS OUTLINE_LEAF(@"SEL$1") INDEX_RS_ASC(@"SEL$1" "T2"@"SEL$1" ("T2"."OBJECT_ID")) END_OUTLINE_DATA */ Predicate Information (identified by operation id): --------------------------------------------------- 2 - access("OBJECT_ID"=4) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - "OBJECT_NAME"[VARCHAR2,128], "OBJECT_ID"[NUMBER,22] 2 - "T2".ROWID[ROWID,10], "OBJECT_ID"[NUMBER,22] Note ----- - SQL plan baseline SQL_PLAN_7bc3aw1b24guz24c6dbb6 used for this statement 50 rows selected.
從上述輸出能夠看出,原目標SQL已經走了新的執行計劃(索引範圍掃描),並且Note部分也有提示「SQL plan baseline SQL_PLAN_7bc3aw1b24guz24c6dbb6 used for this statement」說明走了SPM。