oracle 11G 執行計劃管理

一、oracle 11G 執行計劃管理原理

oracle11G開始,引入了sql執行計劃管理(SQL Plan Management)這個新特性


通過啓用該特性,某條語句如果產生了一個新的執行計劃,只有在它的性能比原來的執行計劃好的情況下,纔會被使用。


優化器維護兩個列表:

plan history

plan baseline


11G也支持手工維護plan history,作爲對自動維護plan history的功能補充

plan baseline是plan history的一個子集


1.初始化參數 OPTIMIZER_CAPTURE_PLAN_BASELINES 設置爲true,則會自動捕獲SQL的執行計劃。


SQL第一次執行,plan history和plan baseline列表都爲空,這時產生的執行計劃會同時進入到plan history,plan baseline列表中

以後同一語句所產生的新執行計劃都會先進入到plan history中,然後同plan baseline中的執行計劃進行比較,只有成本比plan baseline

中的要低纔會進入到plan baseline中


2.使用dbms_spm包手工處理,這可以讓你手工管理SQL Plan baseline。使用該包,你可以直接將SQL的執行計劃從 shared pool里加載到

plan baseline裏,也可以將已經存在的SQL Tuning Set加載到plan baseline裏。同時,dbms_spm還可以將plan history裏的執行計劃加入到

plan baseline裏。反之也可以用該包將plan baseline裏的執行計劃移出去。


3.plan baseline 裏的執行計劃是如何被使用的呢?

oracle 提供了一個初始化參數:OPTIMIZER_USE_PLAN_BASELINES,該參數缺省爲true,表示要求優化器考慮使用plan baseline裏的執行計劃,

每次優化器解析SQL語句的時候,首先仍然使用11G之前的傳統方式產生一個成本最低的執行計劃,然後看初始化參數:

OPTIMIZER_USE_PLAN_BASELINES是否設置爲true,如果爲false,則直接返回所生成的執行計劃。否則如果爲true,則去plan_history裏找是否存在

相同的執行計劃,如果找到,則再去plan baseline裏找是否存在相同的執行計劃,如果也找到了,則直接返回該執行計劃。如果在plan_history裏沒找到

相同的執行計劃,則將生成的執行計劃加入到plan history裏,然後將執行計劃與plan baseline裏已經存在的進行比較,看哪個成本低就選取哪個執行計劃


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


二、執行計劃管理的測試

oracle11g提供了一個視圖:dba_sql_plan_baselines,可以在該視圖裏查詢某條 SQL語句相關的plan history以及plan baseline。我們來看下面的例子

首先創建一個測試表.

SQL> create table t1(skew number,padding varchar2(100));

Table created.

SQL> 
SQL> insert into t1 select rownum,object_name from dba_objects;

86632 rows created.

SQL> commit;
SQL> set autot trace exp stat
SQL> select * from t1 where skew=200;


Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013

--------------------------------------------------------------------------
| Id  | Operation	  | Name | Rows  | Bytes | Cost (%CPU)| Time	 |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |	 |     5 |   325 |   116   (1)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| T1	 |     5 |   325 |   116   (1)| 00:00:02 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("SKEW"=200)

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
	 10  recursive calls
	  0  db block gets
	497  consistent gets
	  0  physical reads
	  0  redo size
	607  bytes sent via SQL*Net to client
	524  bytes received via SQL*Net from client
	  2  SQL*Net roundtrips to/from client
	  2  sorts (memory)
	  0  sorts (disk)
	  1  rows processed

SQL> /


Execution Plan
----------------------------------------------------------
Plan hash value: 3617692013

--------------------------------------------------------------------------
| Id  | Operation	  | Name | Rows  | Bytes | Cost (%CPU)| Time	 |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |	 |     5 |   325 |   116   (1)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| T1	 |     5 |   325 |   116   (1)| 00:00:02 |
--------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("SKEW"=200)

Note
-----
   - dynamic sampling used for this statement (level=2)


Statistics
----------------------------------------------------------
	  0  recursive calls
	  0  db block gets
	423  consistent gets
	  0  physical reads
	  0  redo size
	607  bytes sent via SQL*Net to client
	524  bytes received via SQL*Net from client
	  2  SQL*Net roundtrips to/from client
	  0  sorts (memory)
	  0  sorts (disk)
	  1  rows processed
SQL> select * from dba_sql_plan_baselines;

no rows selected

儘管執行兩次,但是這時去查詢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;

Session altered.

SQL> select * from t1 where skew=200;

      SKEW
----------
PADDING
--------------------------------------------------------------------------------
       200
I_SQL$TEXT_PKEY


SQL> /

      SKEW
----------
PADDING
--------------------------------------------------------------------------------
       200
I_SQL$TEXT_PKEY


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					   ENABLED   ACCEPTED  AUTOPURGE
------------------------------------------ --------- --------- ---------
1.2376E+19
SQL_abc0a2c042fa089c
SQL_PLAN_arh52s11gn24wdbd90e8e
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表示是否被啓用了;如果某個執行計劃爲禁用,則優化器根本就不會考慮使用該計劃;

accepted表示是否接受,也就是是否進入了plan baseline。

autopurge表示是否爲定期自動刪除。


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

SQL> create index idx_skew on t1(skew);

Index created.
SQL> exec dbms_stats.gather_table_stats('SYS','T1',cascade=>true);

PL/SQL procedure successfully completed.

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 				    ENABLED   ACCEPTED	FIXED	  AUTOPURGE
---------- ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ ------------------------------------------ --------- --------- --------- ---------
1.2376E+19 SQL_abc0a2c042fa089c 								      SQL_PLAN_arh52s11gn24w22142e90							     AUTO-CAPTURE				    YES       NO	NO	  YES
1.2376E+19 SQL_abc0a2c042fa089c 								      SQL_PLAN_arh52s11gn24wdbd90e8e							     AUTO-CAPTURE				    YES       YES	NO	  YES

這時我們可以看到,dba_sql_plan_baselines視圖裏多了一個執行計劃,也就是我們後面那個使用了索引掃描的執行計劃。而該執行計劃的accepted爲NO,說明該計劃並沒有

進入到plan baseline裏,但進入了plan history裏。

這時我們可以通過調用dbms_spm包來手工將走索引的執行計劃加入到plan baseline裏。如下所示,將accepted改爲YES。


執行DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE前:

SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge from dba_sql_plan_baselines where plan_name='SQL_PLAN_arh52s11gn24w22142e90';

 SIGNATURE SQL_HANDLE										      PLAN_NAME 									     ORIGIN 				    ENABLED   <span style="color:#ff0000;">ACCEPTED	</span>FIXED	  AUTOPURGE
---------- ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ ------------------------------------------ --------- --------- --------- ---------
1.2376E+19 SQL_abc0a2c042fa089c 								      SQL_PLAN_arh52s11gn24w22142e90							     AUTO-CAPTURE				    YES       <span style="color:#ff0000;">NO	</span>NO	  YES


執行DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE後:
SQL> declare
  l_plans_altered clob;
begin
  l_plans_altered := DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE(sql_handle => 'SQL_abc0a2c042fa089c',
                                                       plan_name  => 'SQL_PLAN_arh52s11gn24w22142e90',
                                                       time_limit => DBMS_SPM.AUTO_LIMIT,
                                                       verify     => 'yes',
                                                       commit     => 'yes');
end;  2    3    4    5    6    7    8    9  
 10  /

PL/SQL procedure successfully completed.

SQL>                               
SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge from dba_sql_plan_baselines where plan_name='SQL_PLAN_arh52s11gn24w22142e90';

 SIGNATURE SQL_HANDLE										      PLAN_NAME 									     ORIGIN 				    ENABLED   <span style="color:#ff0000;">ACCEPTED	</span>FIXED	  AUTOPURGE
---------- ------------------------------------------------------------------------------------------ ------------------------------------------------------------------------------------------ ------------------------------------------ --------- --------- --------- ---------
1.2376E+19 SQL_abc0a2c042fa089c 								      SQL_PLAN_arh52s11gn24w22142e90							     AUTO-CAPTURE				    YES       <span style="color:#ff0000;">YES</span>	NO	  YES

SQL> 

不過後來發現,要把accepted變爲NO卻是不可以了,只有先刪除,然後再重新生成讓優化器自動加入到plan history中

SQL> DECLARE
  l_plans_dropped PLS_INTEGER;
BEGIN
  l_plans_dropped := DBMS_SPM.drop_sql_plan_baseline(sql_handle => 'SQL_abc0a2c042fa089c',
                                                     plan_name  => 'SQL_PLAN_arh52s11gn24w22142e90');
end;  2    3    4    5    6  
  7  /

PL/SQL procedure successfully completed.


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章