1. 程式人生 > >點評Oracle 11g新特性之執行計劃管理

點評Oracle 11g新特性之執行計劃管理

摘自:http://doc.chinaunix.net/oracle/200707/156806.shtml
 
【內容導航】
第1頁:執行計劃管理的工作原理
第2頁:執行計劃管理的測試
    摘要:本文描述了11g的新特性之一:執行計劃管理,介紹了引入該新特性的原因,以及該新特性的相關特點、工作原理等。最後通過引入一個測試案例來介紹如何使用該新特性。


1. 執行計劃管理的工作原理 
    我們知道,SQL語句的效能很大程度上依賴於SQL語句的執行計劃。如果SQL語句的執行計劃發生改變,則SQL的效能很有可能發生大的變化。而SQL執行計劃發生變化的原因有很多種,包括優化器版本的變化、統計資訊的變化、優化器相關的各種引數的變化、新增或刪除了索引、新增或刪除了物化檢視、修改了系統設定、以及是否應用了10g引入的SQL profile等。


    在11g之前,我們可以使用儲存大綱(stored outline)和SQL Profile來幫助我們固定某條SQL語句的執行計劃,防止由於執行計劃發生變化而導致的效能下降。不過這些技術需要DBA人為的處理,比如儲存大綱,需要DBA手工建立,而SQL Profile來說,則要DBA手工應用才能生效。 


    從11g開始,oracle引入了SQL執行計劃管理(SQL Plan Management)這個新特性,從而可以讓系統自動的來控制SQL語句執行計劃的穩定性,進而防止由於執行計劃發生變化而導致的效能下降。


    通過啟用該特性,某條語句如果產生了一個新的執行計劃,只有在它的效能比原來的執行計劃好的情況下,才會被使用。 
為了實現執行計劃管理,優化器會為所有執行次數超過一次的SQL語句維護該SQL語句的每個執行計劃的歷史列表(plan history)。優化器通過維護一個語句執行的日誌條目(statement log)來識別該SQL語句是否為第二次執行。一旦優化器認出某條SQL語句為第二次執行,則優化器將該語句所生成的所有不同的執行計劃插入到plan history的相關表裡,而plan history裡包含了優化器能夠用於重新生成執行計劃的所有資訊,這些資訊包括SQL文字、儲存大綱、繫結變數以及解析環境(比如optimizer_mode之類影響優化器解析SQL語句的引數)等。


    當然,11g也支援手工維護SQL語句的plan history,作為對自動維護plan history的功能補充。 
但是並不是說plan history裡任何的執行計劃都可以拿來使用。這裡需要先介紹一下所謂的執行計劃基準線(plan baseline)這個概念。plan baseline是plan history的一個子集,plan baseline裡面的執行計劃是用來比較效能好壞的一個依據。也就是說,憑什麼來判斷是否可以使用一個新產生的執行計劃呢?就是把該新的執行計劃與plan baseline裡的計劃進行比較來判斷。某個SQL語句的執行計劃可以屬於plan history,但是不一定屬於plan baseline。


注意:每個SQL語句都會有它自己的執行計劃歷史以及執行計劃基準線。 


那麼某個SQL語句的執行計劃是如何進入執行計劃歷史,乃至執行計劃基準線的呢? 
有兩種方法可以將SQL語句的執行計劃納入到執行計劃管理體系中去: 
1) 將初始化引數:OPTIMIZER_CAPTURE_PLAN_BASELINES設定為true,則會自動的捕獲SQL的執行計劃。該引數預設為false。設定為true以後,當某條SQL語句第一次執行時,該SQL語句的plan history是空的,顯然該SQL語句的plan baseline也是空的。那麼當該SQL第二次再次執行時,優化器會自動將該SQL語句以及相關的執行計劃放入plan history,同時也會放入到plan baseline裡。這就構成了最初的plan baseline,也就是說最初進入plan history的執行計劃會直接自動進入plan baseline裡。那麼當你做了某些修改,比如添加了一個索引等,然後第三次執行該同樣的SQL語句,則會產生另外一個不同的執行計劃,這時新的執行計劃會自動進入plan history,但是不會自動進入plan baseline。是否使用該新的執行計劃,則要把該新的執行計劃與plan baseline裡現存的第二次執行SQL時的執行計劃進行比較,如果新的執行計劃成本更低,則會使用新的執行計劃,否則使用plan baseline裡的執行計劃。 


2) 使用dbms_spm包手工處理,這可以讓你手工管理SQL plan baseline。使用該包,你可以直接將SQL的執行計劃從shared pool里加載到plan baseline裡,也可以使用dbms_spm包將已經存在的SQL Tuning Set載入到plan baseline裡。同時,dbms_spm可以讓你把plan history裡的執行計劃加入到plan baseline裡。反之,你也可以使用該包將plan baseline裡的執行計劃移出去。


   注意,某條SQL語句的plan baseline裡的第一個執行計劃可以像上面說的通過設定初始化引數來自動加入,但是如果你希望在plan baseline裡新增該SQL語句的其他新的執行計劃時,則必須使用dbms_spm包手動完成。 


那麼plan baseline裡的執行計劃是如何被使用的呢? 
    Oracle提供了一個初始化引數:OPTIMIZER_USE_PLAN_BASELINES,該引數預設為true,表示要求優化器考 
慮使用plan baseline裡的執行計劃,如果設定為false,則不使用執行計劃管理的特性,而又回到了11g之前的狀況。 
以下描述基於的前提是plan baseline裡已經存在了一個SQL的執行計劃。 


    每次優化器解析SQL語句的時候,首先仍然使用11g之前的傳統方式產生一個成本最低的執行計劃,然後看初始化引數:OPTIMIZER_USE_PLAN_BASELINES是否設定為true,如果為false,則直接返回所生成的執行計劃。否則如果為ture,則去plan history裡找是否存在相同的執行計劃,如果找到了,則再去plan baseline裡找是否存在相同的執行計劃,如果也找到了,則直接返回該執行計劃。如果在plan history裡沒找到相同的執行計劃,則將產生的執行計劃加入到plan history裡,然後將執行計劃與plan baseline裡已經存在的執行計劃進行比較,看哪個執行計劃的成本低就取哪個執行計劃。


    如果你為某個SQL語句儲存了儲存大綱,則為了向下相容,該語句會使用儲存大綱。另外,即使你通過設定初始化引數:OPTIMIZER_CAPTURE_PLAN_BASELINES為true來啟動自動捕獲執行計劃到plan baseline裡,對於使用儲存大綱所生成的執行計劃也不會放入plan baseline裡。


    SQL語句的plan history以及plan baseline所涉及到的表是存放在SQL Management Base (SMB)裡的,SMB裡同樣也存放了SQL Profiles。而SMB是資料字典的一部分,存放在SYSAUX表空間裡。SMB所佔用的空間會自動定期的刪除。 

2. 執行計劃管理的測試
    Oracle 11g提供了一個檢視:dba_sql_plan_baselines,可以在該視圖裡查詢某條SQL語句相關的plan 
history以及plan baseline。我們來看下面的例子。 
首先建立一個測試表。 

SQL> create table t1(skew number,padding varchar2(100));
SQL> insert into t1 select rownum,object_name from dba_objects;
SQL> commit;
SQL> set autotrace traceonly exp
stat; SQL> select * from t1 where skew=200; SQL> select * from t1 where skew=200;

    儘管執行兩次,但是這時去查詢dba_sql_plan_baselines,試圖找到SQL文字為select * from t1 where skew=200的記錄時,會發現沒有記錄,因為optimizer_capture_sql_plan_baselines預設為false。我們將該引數設定為true以後繼續測試。 

SQL> alter session set optimizer_capture_sql_plan_baselines=
true; SQL> select * from t1 where skew=200; --全表掃描 SQL> select * from t1 where skew=200; --全表掃描 SQL> select signature,sql_handle,plan_name,origin,enabled,accepted, autopurge from dba_sql_plan_baselines where sql_text like 'select * from t1 where skew=200'; SIGNATURE SQL_HANDLE PLAN_NAME ORIGIN ENA ACC AUT ---------- ------------------------ ----------------------------- ----------- --- --- --- 1.2376E+19 SYS_SQL_abc0a2c042fa089c SYS_SQL_PLAN_42fa089c844cb98a AUTO-CAPTURE YES YES YES

    我們可以看到,文字為“select * from t1 where skew=200”的SQL語句在plan history裡產生了一個執行計劃。其中,sql_handle表示SQL語句的控制代碼;plan_name則表示該SQL的執行計劃的名字;origin表示該執行計劃是如何進入plan history的,該列值為AUTO-CAPTURE則說明是由優化器自動加入的,如果為MANUAL則說明是由DBA手工加入的;enabled表示是否被啟用了,YES表示啟用,NO表示禁用。如果某個執行計劃為禁用,則優化器根本就不會考慮使用該執行計劃;accepted表示是否接受,也就是是否進入了plan baseline。我們看到這裡的accepted為YES,說明該SQL的執行計劃進入了plan baseline裡;autopurge表示該執行計劃是否為定期自動刪除,YES表示是,NO表示否。

    我們繼續測試,在skew上新增一個索引,從而讓原來的SQL不走全表掃描,而改走索引掃描。 
   

SQL> create index idx_t1 on t1(skew);
SQL> exec dbms_stats.gather_table_stats(user,'t1',cascade=>true);
SQL> select * from t1 where skew=200; --索引掃描 SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge
from dba_sql_plan_baselines where sql_text like 'select * from t1 where skew=200';
SIGNATURE SQL_HANDLE PLAN_NAME ORIGIN ENA ACC AUT
---------- ------------------------ ----------------------------- ----------- --- --- --- 1.2376E+19 SYS_SQL_abc0a2c042fa089c SYS_SQL_PLAN_42fa089c844cb98a AUTO-CAPTURE YES YES YES
1.2376E+19 SYS_SQL_abc0a2c042fa089c SYS_SQL_PLAN_42fa089cdbd90e8e AUTO-CAPTURE YES NO YES

    這時我們可以看到,dba_sql_plan_baselines視圖裡多了一個執行計劃,也就是我們後面那個使用了索引掃描的執行計劃。而該執行計劃的accepted為NO,說明該計劃並沒有進入plan baseline裡,但是進入了plan history裡。 
這時,我們可以通過呼叫dbms_spm包來手工將走索引的執行計劃加入到plan baseline裡。如下所示,將accepted改為YES。 

SQL> dbms_spm.alter_sql_plan_baseline(
sql_handle => 'SYS_SQL_abc0a2c042fa089c',
plan_name => 'SYS_SQL_PLAN_42fa089c844cb98a',
attribute_name => 'ACCEPTED',
attribute_value => 'YES'); 

    然後再次查詢dba_sql_plan_baselines檢視,可以發現後面的執行計劃的accepted變為了YES。

SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge
from dba_sql_plan_baselines where sql_text like 'select * from t1 where skew=200';
SIGNATURE SQL_HANDLE PLAN_NAME ORIGIN ENA ACC AUT
---------- ------------------------ ----------------------------- ----------- --- --- --- 1.2376E+19 SYS_SQL_abc0a2c042fa089c SYS_SQL_PLAN_42fa089c844cb98a AUTO-CAPTURE YES YES YES
 1.2376E+19 SYS_SQL_abc0a2c042fa089c SYS_SQL_PLAN_42fa089cdbd90e8e AUTO-CAPTURE YES YES YES

  如果我們要手工刪除plan baseline裡的執行計劃,則可以呼叫dbms_spm裡的儲存過程來實現。 
SQL> var cnt number; 
 SQL> exec :cnt := dbms_spm.purge_sql_plan_baseline('SYS_SQL_abc0a2c042fa089c'); 

  刪除指定SQL語句的執行計劃以後,再去查詢dba_sql_plan_baselines就會發現上面測試SQL語句的執行計劃不存在了。 

  從上面的描述可以看出,SQL Plan Management特性的主要作用就是通過引入一個SQL plan baseline,從而保證SQL語句執行計劃的穩定,進而保證系統性能的穩定。本質上,它屬於11g之前的儲存大綱的升級版,而且是自動實現的,不需要人工干預。