SQL Plan Management

eric0435發表於2016-05-27

任何資料庫應用程式的效能都嚴重依賴於它的查詢執行。當沒有任何使用者介入時Oracle最佳化器是完全能夠評估最優執行計劃的,SQL語句的執行計劃因為各種原因,比如:重新收集最佳化器統計資訊,改變最佳化器引數或方案/後設資料定義而可能會出現改變。但是不能保證執行計劃的改變總是會提高效能,因此會導致有些管理員會鎖定SQL的執行計劃(Stored Outline)或鎖定統計資訊。然而,這樣做會導致不能使用新版最佳化器為了提供高SQL效能所提供的一些新特性或新的訪問路徑。

Oracle的每一個新版本中都包含了一些新特性用來提高查詢的效能。然而某些應用(或部分應用)是靜態的並且比起在特定情況下提高效能來說可預測的效能是更可取的。Oracle11G提供了SPM來完全透時的控制執行計劃的演變。使用SPM最佳化器自動管理執行計劃並且確保只有已經或被驗證的執行計劃才會被使用。當找到SQL語句的新執行計劃時,但直到它被資料庫進行驗證或其效能比當前執行計劃高才會被使用。

SQL Plan Management是一種預防機制,記錄與評估SQL語句的執行計劃。這種機制可以建立一個SQL執行計劃基線,它是由一組已知效能良好的執行計劃組成。不管系統發生何種改變,SQL執行計劃基線被用來維護相關SQL的效能,提供了執行計劃的穩定性。

SPM確保SQL的效能不會因為執行計劃的改變而降低。為了保證這一點,只有SQL執行計劃ACCEPTED為YES才會被最佳化器所使用。

SPM有三個主要元件:
1.SQL執行計劃基線捕獲
建立SQL執行計劃基線這代表對所有相關SQL語句授受這個執行計劃。SQL執行計劃基線被儲存在SYSAUX表空間中的SQL Management BASE中的plan history中,可以透過dba_sql_plan_baselines檢視進行查詢。

2.SQL執行計劃基線選擇
確保只有ACCEPTED為YES的執行計劃才會被使用,使用SQL執行計劃基線並在plan history中跟蹤所有新的執行計劃。plan history由ACCEPTED為NO與ACCEPTED為YES的執行計劃組成。ACCEPTED為NO的執行計劃可能是沒有被驗證或者被拒絕(驗證了但效能比當前使用的執行計劃要差)

3.SQL執行計劃基線演進
對plan history中的所有沒有被驗證的執行計劃進行評估讓其成為接受的或拒絕的執行計劃

SQL執行計劃基線捕獲
為了讓SPM起作用必須首先使用當前基於成本的執行計劃來作為SQL Management Base,這將成為每個SQL語句的SQL執行計劃基線。有兩種不同的方法來建立SQL Management Base:
.自動捕獲執行計劃
.批次載入執行計劃

自動捕獲執行計劃
自動捕獲執行計劃是由引數optimizer_capture_sql_plan_baselines=true來開啟的(預設值為false)當自動捕獲執行計劃被啟用時,SPM檔案庫將會自動儲存任何重複執行的SQL語句的執行計劃。為了識別重複執行的SQL語句,最佳化器將會在每個SQL語句第一次被編譯時進行標識,如果這個SQL語句再次被執行或編譯,那麼就會將這個SQL語句標記為重複執行的SQL,將會為這個SQL語句建立SQL plan history,它將包含生成的執行計劃,比如:SQL文字,儲存概要,綁當定變數與編譯環境等資訊。當前基於成本的執行計劃將會作為SQL語句的第一個SQL執行計劃基線並且這個執行計劃的ACCEPTED會標記為YES,只有ACCEPTED為YES的執行計劃才會被使用,如果將來對於這個SQL語句產生了新的執行計劃,這個執行計劃將會增加到plan history中並且將會被標記為驗證過的。只有當它的效能比當前所使用的執行計劃更好時才會將ACCEPTED標記為YES。

批次載入執行計劃
批次載入執行計劃在資料庫從之前的版本升級致電Oracle 11g或部署新應用程式時很有用。批次載入可以與自動載入執行計劃結合使用或者代替自動載入執行計劃。執行計劃被批次載入時會自動接受建立的新SQL執行計劃基線或者向已經存在的增加一個。SQL anagement BASE可以使用三種不同的方法來批次載入執行計劃。
1.從指定的SQL Tuning Set(STS)中載入執行計劃

SQL> BEGIN
  2  DBMS_SQLTUNE.CREATE_SQLSET(
  3  sqlset_name => 'my_sql_tuning_set',
  4  description => 'TEST');
  5  END;
  6  /
 
PL/SQL procedure successfully completed

SQL> DECLARE
  2    l_cursor  DBMS_SQLTUNE.sqlset_cursor;
  3  BEGIN
  4    OPEN l_cursor FOR
  5      SELECT VALUE(p)
  6      FROM   TABLE (DBMS_SQLTUNE.select_cursor_cache (
  7                      NULL, -- basic_filter
  8                      NULL, -- object_filter
  9                      NULL, -- ranking_measure1
 10                      NULL, -- ranking_measure2
 11                      NULL, -- ranking_measure3
 12                      NULL, -- result_percentage
 13                      2,    -- result_limit
                         'all') --attribute_list    
 14                    ) p;
 15  
 16    DBMS_SQLTUNE.load_sqlset (
 17      sqlset_name     => 'my_sql_tuning_set',
 18      populate_cursor => l_cursor);
 19  END;
 20  /
 
PL/SQL procedure successfully completed

或者從awr中載入

SQL> DECLARE
  2    l_cursor  DBMS_SQLTUNE.sqlset_cursor;
  3  BEGIN
  4    OPEN l_cursor FOR
  5      SELECT VALUE(p)
  6      FROM   TABLE (DBMS_SQLTUNE.select_workload_repository (
  7                      29027,  -- begin_snap
  8                      29028,  -- end_snap
  9                      NULL, -- basic_filter
 10                      NULL, -- object_filter
 11                      NULL, -- ranking_measure1
 12                      NULL, -- ranking_measure2
 13                      NULL, -- ranking_measure3
 14                      NULL, -- result_percentage
 15                      2,   -- result_limit
 16                      'all'--attribute_list
 17                      )
 18                    ) p;
 19  
 20    DBMS_SQLTUNE.load_sqlset (
 21      sqlset_name     => 'my_sql_tuning_set',
 22      populate_cursor => l_cursor);
 23  END;
 24  /
 
PL/SQL procedure successfully completed
SQL> select * from dba_sqlset where name='my_sql_tuning_set';
 
        ID NAME                           OWNER                          DESCRIPTION                                                                      CREATED     LAST_MODIFIED STATEMENT_COUNT
---------- ------------------------------ ------------------------------ -------------------------------------------------------------------------------- ----------- ------------- ---------------
        15 my_sql_tuning_set              INSUR_CHANGDE                  TEST                                                                             2016/5/26 1 2016/5/26 12:               2
 
SQL> select * from dba_sqlset_statements where sqlset_name='my_sql_tuning_set';
 
SQLSET_NAME                    SQLSET_OWNER                    SQLSET_ID SQL_ID        FORCE_MATCHING_SIGNATURE SQL_TEXT                                                                         PARSING_SCHEMA_NAME            PARSING_SCHEMA_ID PLAN_HASH_VALUE BIND_DATA                                                                        BINDS_CAPTURED MODULE                                           ACTION                           ELAPSED_TIME   CPU_TIME BUFFER_GETS DISK_READS DIRECT_WRITES ROWS_PROCESSED    FETCHES EXECUTIONS END_OF_FETCH_COUNT OPTIMIZER_COST OPTIMIZER_ENV                                                                      PRIORITY COMMAND_TYPE FIRST_LOAD_TIME     STAT_PERIOD ACTIVE_STAT_PERIOD OTHER                                                                            PLAN_TIMESTAMP    SQL_SEQ
------------------------------ ------------------------------ ---------- ------------- ------------------------ -------------------------------------------------------------------------------- ------------------------------ ----------------- --------------- -------------------------------------------------------------------------------- -------------- ------------------------------------------------ -------------------------------- ------------ ---------- ----------- ---------- ------------- -------------- ---------- ---------- ------------------ -------------- -------------------------------------------------------------------------------- ---------- ------------ ------------------- ----------- ------------------ -------------------------------------------------------------------------------- -------------- ----------
my_sql_tuning_set              INSUR_CHANGDE                          15 2823agph489xc        1.702412129134E19 select id,name,password from gl_czy where name ='系統管理'                       ZW4001                                       248      2543410975                                                                                                 R9_AppSrv.EXE                                                                           124908      32105         324         48             0             21         42         21                 21              3 E289FB89A4E49800CE001000AEF9C3E2CFFA3310564145555195A110555555154554555859155544                       3                                                                                                                                     2016/2/16 10:5        717
 
my_sql_tuning_set              INSUR_CHANGDE                          15 1hfffsrmgqhwp      1.11129101236943E19 select nvl(catalog_center,center_id) as  catalog_center from bs_hospital_collate INSUR_CHANGDE                                211      2429242715                                                                                                 JDBC Thin Client                                                                        141372     141372       11475          0             0           3825       3825       3825               3825              1 E289FB89A4E49800CE001000AEF9C3E2CFFA3310564145555195A110555555154554555859155544                       3                                                                                                                                     2016/5/23 14:2        718
 
SQL> exec dbms_sqltune.create_stgtab_sqlset(table_name => ‘TABLE_SQLSET’,schema_name 

=> ‘JY’);

PL/SQL procedure successfully completed

SQL> exec dbms_sqltune.pack_stgtab_sqlset(sqlset_name => 

‘my_sql_tuning_set’,staging_table_name => ‘TABLE_SQLSET’,staging_schema_owner =>’JY

’);

PL/SQL procedure successfully completed


匯出儲存STS

[IBMP740-1:oracle:/yb_oradata/RLZYbak]$expdp jy/jy directory=dump_RLZY dumpfile=stgtab_sqlset.dmp logfile=stgtab_sqlset.log tables=TABLE_SQLSET                         

                                < Export: Release 10.2.0.4.0 - 64bit Production on Thursday, 26 May, 2016 16:57:34

Copyright (c) 2003, 2007, Oracle.  All rights reserved.

Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Starting "INSUR_CHANGDE"."SYS_EXPORT_TABLE_01":  insur_changde/******** directory=dump_RLZY dumpfile=stgtab_sqlset.dmp logfile=stgtab_sqlset.log tables=TABLE_SQLSET 
Estimate in progress using BLOCKS method...
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
Total estimation using BLOCKS method: 576 KB
Processing object type TABLE_EXPORT/TABLE/TABLE
Processing object type TABLE_EXPORT/TABLE/INDEX/INDEX
. . exported "INSUR_CHANGDE"."TABLE_SQLSET"              16.91 KB       2 rows
. . exported "INSUR_CHANGDE"."TABLE_SQLSET_CPLANS"       24.10 KB       5 rows
. . exported "INSUR_CHANGDE"."TABLE_SQLSET_CBINDS"       9.507 KB       0 rows
Master table "INSUR_CHANGDE"."SYS_EXPORT_TABLE_01" successfully loaded/unloaded
******************************************************************************
Dump file set for INSUR_CHANGDE.SYS_EXPORT_TABLE_01 is:
  /bak/dpdump/stgtab_sqlset.dmp
Job "INSUR_CHANGDE"."SYS_EXPORT_TABLE_01" successfully completed at 16:59:25

匯入STS

[oracle@jyrac1 ~]$ impdp jy/jy directory=dump_dir dumpfile=stgtab_sqlset.dmp remap_schema=insur_changde:jy remap_tablespace=hygeia:users

Import: Release 11.2.0.4.0 - Production on Thu May 26 17:53:08 2016

Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - Production
With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP,
Data Mining and Real Application Testing options
Master table "JY"."SYS_IMPORT_FULL_01" successfully loaded/unloaded
Starting "JY"."SYS_IMPORT_FULL_01":  jy/******** directory=dump_dir dumpfile=stgtab_sqlset.dmp remap_schema=insur_changde:jy remap_tablespace=hygeia:users 
Processing object type TABLE_EXPORT/TABLE/TABLE
Processing object type TABLE_EXPORT/TABLE/TABLE_DATA
. . imported "JY"."TABLE_SQLSET"                         16.91 KB       2 rows
. . imported "JY"."TABLE_SQLSET_CPLANS"                  24.10 KB       5 rows
. . imported "JY"."TABLE_SQLSET_CBINDS"                  9.507 KB       0 rows
Processing object type TABLE_EXPORT/TABLE/INDEX/INDEX
Job "JY"."SYS_IMPORT_FULL_01" successfully completed at Thu May 26 17:59:33 2016 elapsed 0 00:06:05

unpack STS

SQL> begin
  2    DBMS_SQLTUNE.UNPACK_STGTAB_SQLSET(sqlset_name          => 'my_sql_tuning_set',
  3                                      sqlset_owner         => 'JY',
  4                                      replace              => true,
  5                                      staging_table_name   => 'TABLE_SQLSET',
  6                                      staging_schema_owner => 'JY');
  7  END;
  8  /
PL/SQL procedure successfully completed

從STS載入SQL執行計劃基線

SQL> declare
  2  ret number;
  3  begin
  4  ret := dbms_spm.load_plans_from_sqlset(sqlset_name => 'my_sql_tuning_set',sqlset_owner => 'INSUR_CHANGDE');
  5  end;
  6  /
  
 
PL/SQL procedure successfully completed

SQL> select sql_handle, plan_name,origin, enabled, accepted,sql_text from dba_sql_plan_baselines where parsing_schema_name in('ZW4001','INSUR_CHANGDE');
 
SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENABLED ACCEPTED SQL_TEXT
------------------------------ ------------------------------ -------------- ------- -------- 

--------------------------------------------------------------------------------
SQL_c4a3ce0d598be4e4           SQL_PLAN_c98yf1pcsrt74ebcd9fdf MANUAL-LOAD    YES     YES      select id,name,password from gl_czy where name ='系統管理'
 
SQL_b9bc48036c46e780           SQL_PLAN_bmg280dq4dtw0e85be7cc MANUAL-LOAD    YES     YES      select nvl(catalog_center,center_id) as  catalog_center from 

bs_hospital_collate
 

2.使用Cursor Cache中的執行計劃
可以從cursor cache中直接載入SQL語句的執行計劃到SQL Management Base中。可以透過module名,方案或SQL_ID來進過濾,可以用來標記想要捕獲的SQL語句或一組SQL語句。

SQL> set autotrace traceonly
SQL> select * from t1 where c1>4076;

924 rows selected.


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

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



SQL> select sql_text,sql_id,plan_hash_value from v$sqlarea where sql_text like '%c1>4076%';
 
SQL_TEXT                                                                         SQL_ID        PLAN_HASH_VALUE
-------------------------------------------------------------------------------- ------------- ---------------
select * from t1 where c1>4076                                                   0006gg4zsmmcg      3617692013


SQL> var n number
SQL> begin
  2  :n:=dbms_spm.load_plans_from_cursor_cache(sql_id=>'0006gg4zsmmcg', plan_hash_value=>'3617692013', fixed =>'NO', enabled=>'YES');
  3  end;
  4  /

PL/SQL procedure successfully completed.

SQL> select sql_handle, plan_name,origin, enabled, accepted,sql_text  from dba_sql_plan_baselines  where sql_text like 'select %c1>4076';
 
SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENABLED ACCEPTED SQL_TEXT
------------------------------ ------------------------------ -------------- ------- -------- 

--------------------------------------------------------------------------------
SQL_67b129b37635284b           SQL_PLAN_6gc99qdv3aa2bdbd90e8e MANUAL-LOAD    YES     YES      select * from t1 where c1>4076


3.從staging table中unpack SQL執行計劃基線
在原系統中建立staing表

SQL> set autotrace traceonly 
SQL> select * from t1 where c1>4076;

924 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1369807930

---------------------------------------------------------------------------
| Id  | Operation        | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT |        |   924 |  3696 |     4   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_T1 |   924 |  3696 |     4   (0)| 00:00:01 |
---------------------------------------------------------------------------

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

   1 - access("C1">4076)

Note
-----
   - SQL plan baseline "SQL_PLAN_6gc99qdv3aa2bbeaed07c" used for this statement


SQL> exec dbms_spm.create_stgtab_baseline(table_name => 'BASELINE_TABLE',table_owner => 'JY');
 
PL/SQL procedure successfully completed

將SQL執行計劃基線從SQL Management Base中載入到staing table中

SQL> declare
  2  x number;
  3  begin
  4   x:=dbms_spm.pack_stgtab_baseline(table_name => 'BASELINE_TABLE',table_owner => 'JY',creator =>'JY');
  5  end;
  6  /
  
PL/SQL procedure successfully completed

SQL> declare
  2  cursor c is select sql_handle, plan_name,origin, enabled, accepted,sql_text from dba_sql_plan_baselines where parsing_schema_name in('JY');
  3  x number;
  4  begin
  5   for i in c loop
  6    x:=dbms_spm.drop_sql_plan_baseline(sql_handle => ''||i.sql_handle,plan_name => ''||i.plan_name);
  7   end loop;
  8  end;
  9  /
 
PL/SQL procedure successfully completed

SQL> select * from t1 where c1>4076;

924 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1369807930

---------------------------------------------------------------------------
| Id  | Operation        | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT |        |   924 |  3696 |     4   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_T1 |   924 |  3696 |     4   (0)| 00:00:01 |
---------------------------------------------------------------------------

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

   1 - access("C1">4076)


匯出staing table並在目標資料庫中匯入,這裡省略了相關操作。在目標資料庫將SQL執行計劃基線從staging table中載入到SQL Management Base中

SQL> declare
  2  x number;
  3  begin
  4   x:=dbms_spm.unpack_stgtab_baseline(table_name => 'BASELINE_TABLE',table_owner => 'JY');
  5  end;
  6  /
 
PL/SQL procedure successfully completed


SQL> select * from t1 where c1>4076;

924 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1369807930

---------------------------------------------------------------------------
| Id  | Operation        | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT |        |   924 |  3696 |     4   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_T1 |   924 |  3696 |     4   (0)| 00:00:01 |
---------------------------------------------------------------------------

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

   1 - access("C1">4076)

Note
-----
   - SQL plan baseline "SQL_PLAN_6gc99qdv3aa2bbeaed07c" used for this statement

SQL執行計劃基線選擇
每次SQL被編譯時,最佳化器首先使用傳統的基於成本的方法來建立一個最優執行計劃。如果引數optimizer_use_plan_baselines設定為true(預設值),那麼在基於成本的執行計劃被執行之前,最佳化器將嘗試在SQL語句的SQL執行計劃基線中找到一個匹配的執行計劃,這是作為記憶體操作來執行的,如果找到了匹配的執行計劃將使用該執行計劃。否則,將生成一個新的執行計劃並增加到plan history中,在執行計劃被授受之前必須被驗證。最佳化器將從該SQL所關聯的所有執行計劃中選擇一個成本最低的來執行。然而,如果系統的改變造成所有已經接受的執行計劃不能重現,那麼最佳化器將會使用新的執行計劃。

SQL執行計劃基線也可能影響最佳化器對執行計劃的選擇。SQL執行計劃基線可以被標記為固定(fixed),Fixed的SQL執行計劃基線指示最佳化器會優先選擇。如果最佳化器正在評估SQL執行計劃基線的成本並且有一個執行計劃是fixed,並且fixed的執行計劃可以重現,那麼最佳化器只會評估fixed執行計劃的成本。如果fixed的執行計劃不可以重現,那麼最佳化器將會評估其它的SQL執行計劃基線並從其中選擇一個成本最低的執行計劃。評估一個執行計劃的成本遠不及硬解析那樣昂貴。最佳化器不會考慮所有可能的訪問方法,只會考慮特定的訪問方法。

SQL執行計劃的演進
當最佳化器為SQL語句找到一個新執行計劃時,這個新的執行計劃會作為未被接受的執行計劃被增加到plan history中,在它成為接受(ACCEPTED=YES)的執行計劃之前需要被驗證。可以透過使用EM或執行dbms_spm.evolve_sql_plan_baseline來演進。使用這些方法有三種選擇:
1.只有新執行計劃比現有的SQL執行計劃基線效能更好才將ACCEPTED設定為YES
2.不進行效能驗證就將ACCEPTED設定為YES
3.執行效能比較並生成一個報告但不演進新的執行計劃

如果選擇選項1,它將觸發新的執行計劃被評估來比較是否它的效能要比被選擇的執行計劃好。如果是,那麼新的執行計劃會被增加到SQL執行計劃基線並且ACCEPTED設定為YES。否則將新執行計劃的ACCEPTED設定為NO並增加到plan history中,但它的last_verified屬性將更新為當前時間戳,並且會返回一個格式化的文字報告,它包含了新執行計劃與原執行計劃的效能統計資料。

如果選擇選項2,新執行計劃將會增加到SQL執行計劃基線中,而不對效能進行驗證並將ACCEPTED設定為YES,同樣也會生成報告。

如果選擇選項3,將會驗證新執行計劃的效能是否比已選擇的執行計劃好,但是就算效能更好也會不自動將新執行計劃的ACCEPTED設定為YES,在評估之後只會生成報告。

SQL Management Base的使用與管理
有兩個引數用來控制SPM
1.optimizer_capture_sql_plan_baselines:對重複執行的SQL語句是否自動捕獲新的SQL執行計劃基線。預設值是false。

2.optimizer_use_sql_plan_baselines:控制最佳化器是否使用SQL執行計劃基線。當啟用時,最佳化器在編譯SQL語句時會查詢SQL執行計劃基線中的執行計劃。如果找到,最佳化器將會從SQL執行計劃基線中選擇一個成本最低的執行計劃。預設值是true。

SQL Management Base空間消耗的管理
statment log,plan histories與SQL執行計劃基線都被儲存在SQL Management Base中。SQL Management Base是資料庫資料字典的一部分儲存在SYSAUX表空間中。預設情況下,SQL Management Base的空間限制不會超過SYSAUX表空間的10%。但是也可以使用dbms_spm.configure來進行修改讓其空間限制處於SYSAUX表空間的1%到50%之間。每週後臺程式都會檢測SQL Management Base所佔用的空間大小,並且當使用空間超過設定的限制,程式就會向alert.log記錄一條警告資訊。也有一個每週排程清除作業來管理SQL Management Base所佔用的空間。在維護視窗內這個任務會自動執行並且任何超過53周沒有被使用過的執行計劃將會被清除,因此確保只有SQL語句一旦執行就能保證一年之內相關執行計劃是可以使用的。可以使用dbms_spm.configure來將沒使用的執行計劃保留週期修改為5到523周這個範圍之內。

因為SQL Management Base使用SYSAUX表儂間來儲存執行計劃,如果SYSAUX表空間不能使用,那麼SPM也將不能使用。

透過DBA檢視監控SPM
dbs_sql_plan_baselines檢視顯示了關於當前為特定SQL語句所建立的SQL執行計劃基線。

SQL> select sql_handle, plan_name,origin, enabled, accepted,sql_text,fixed,autopurge from dba_sql_plan_baselines where parsing_schema_name in('JY') and 

sql_handle='SQL_67b129b37635284b';
 
SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENABLED ACCEPTED SQL_TEXT                                                                  

       FIXED AUTOPURGE
------------------------------ ------------------------------ -------------- ------- -------- 

-------------------------------------------------------------------------------- ----- ---------
SQL_67b129b37635284b           SQL_PLAN_6gc99qdv3aa2bbeaed07c AUTO-CAPTURE   YES     YES      select * from t1 where c1>4076                                            

       NO    YES
SQL_67b129b37635284b           SQL_PLAN_6gc99qdv3aa2bdbd90e8e MANUAL-LOAD    NO      YES      select * from t1 where c1>4076                                            

       NO    YES

為了檢視任何SQL執行計劃基線的詳細執行計劃可以執行dbms_xplan.display_sql_plan_baseline

SQL> select * from table(dbms_xplan.display_sql_plan_baseline(sql_handle => 'SQL_67b129b37635284b',plan_name => 'SQL_PLAN_6gc99qdv3aa2bdbd90e8e'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SQL handle: SQL_67b129b37635284b
SQL text: select * from t1 where c1>4076
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Plan name: SQL_PLAN_6gc99qdv3aa2bdbd90e8e         Plan id: 3688435342
Enabled: NO      Fixed: NO      Accepted: YES     Origin: MANUAL-LOAD
--------------------------------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |   924 |  3696 |     5   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| T1   |   924 |  3696 |     5   (0)| 00:00:01 |
--------------------------------------------------------------------------
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("C1">4076)
 
24 rows selected
 
SQL> select * from table(dbms_xplan.display_sql_plan_baseline(sql_handle => 'SQL_67b129b37635284b',plan_name => 'SQL_PLAN_6gc99qdv3aa2bbeaed07c'));
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
SQL handle: SQL_67b129b37635284b
SQL text: select * from t1 where c1>4076
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
Plan name: SQL_PLAN_6gc99qdv3aa2bbeaed07c         Plan id: 3199127676
Enabled: YES     Fixed: NO      Accepted: YES     Origin: AUTO-CAPTURE
--------------------------------------------------------------------------------
Plan hash value: 1369807930
---------------------------------------------------------------------------
| Id  | Operation        | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT |        |   924 |  3696 |     4   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_T1 |   924 |  3696 |     4   (0)| 00:00:01 |
---------------------------------------------------------------------------
 
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access("C1">4076)
 
24 rows selected

還可以透過使用v$sql檢視來檢視SQL語句是否使用了SQL執行計劃基線。如果SQL語句正使用SQL執行計劃基線,那麼dba_sql_plan_baselines中的plan_name就會與v$sql中的sql_plan_baseline有相同的值。

select sql_handle, plan_name,origin, enabled, accepted,a.sql_text,fixed,autopurge from dba_sql_plan_baselines a,v$sql b 
where a.parsing_schema_name in('JY') and  a.plan_name=b.sql_plan_baseline and a.signature=b.exact_matching_signature
and a.sql_text like '%select * from t1 where c1>4076%';

SQL執行計劃在以下情況可以用來提高或維護SQL效能:
1.資料庫升級
資料庫升級會安裝新版的最佳化器,這通常會改變一小部分SQL的執行計劃,大部分發生改變的執行計劃效能沒有變化或者有所提高。然而,特定的執行計劃發生改變可能造成效能的衰減。使用SQL執行計劃基線可以有效的最小化由資料庫升級而引起的效能衰減。

2.系統/資料發生變化
當系統/資料發生變化時可能會影響某些SQL的執行計劃,潛在造成效能衰減。使用SQL執行計劃能夠最小化效能衰減並且穩定SQL效能。

3.應用程式升級
開發新的應用程式意味著引入新的SQL語句。在標準測試環境中對於新SQL語句應用程式可能會使用合適的執行計劃。如果你的系統配置不同於測試環境,SQL執行計劃基線可以被用來產生更好的效能。

如果在cursor快取中有效能良好的執行計劃,那麼可以將其載入到SPM中,因此你可以使用SQL執行計劃基數來維護SQL的效能。

SQL> set autotrace traceonly
SQL> select * from t1 where c1>4076;

924 rows selected.


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

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



SQL> select sql_text,sql_id,plan_hash_value from v$sqlarea where sql_text like '%c1>4076%';
 
SQL_TEXT                                                                         SQL_ID        PLAN_HASH_VALUE
-------------------------------------------------------------------------------- ------------- ---------------
select * from t1 where c1>4076                                                   0006gg4zsmmcg      3617692013


SQL> var n number
SQL> begin
  2  :n:=dbms_spm.load_plans_from_cursor_cache(sql_id=>'0006gg4zsmmcg', plan_hash_value=>'3617692013', fixed =>'NO', enabled=>'YES');
  3  end;
  4  /

PL/SQL procedure successfully completed.

SQL> select sql_handle, plan_name,origin, enabled, accepted,sql_text  from dba_sql_plan_baselines  where sql_text like 'select %c1>4076';
 
SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENABLED ACCEPTED SQL_TEXT
------------------------------ ------------------------------ -------------- ------- -------- 

--------------------------------------------------------------------------------
SQL_67b129b37635284b           SQL_PLAN_6gc99qdv3aa2bdbd90e8e MANUAL-LOAD    YES     YES      select * from t1 where c1>4076



SQL> select * from t1 where c1>4076;

924 rows selected.


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

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

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

   1 - filter("C1">4076)

Note
-----
   - SQL plan baseline "SQL_PLAN_6gc99qdv3aa2bdbd90e8e" used for this statement


Statistics
----------------------------------------------------------
         26  recursive calls
         17  db block gets
         89  consistent gets
          0  physical reads
       3060  redo size
      13042  bytes sent via SQL*Net to client
       1091  bytes received via SQL*Net from client
         63  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        924  rows processed

可以看到SQL plan baseline "SQL_PLAN_6gc99qdv3aa2bdbd90e8e" used for this statement資訊,說明對於該SQL語句以後的執行都將會使用所建立的SQL執行計劃基線。

在啟用SPM後,對於這些有了SQL執行計劃基線的SQL_ID,資料庫將不會再收集新的執行計劃(即使在SPM被禁用的情況下也不會再收集新的執行計劃)。

SPM預設值就是啟用,自動捕獲SQL執行計劃基線是禁用的

SQL> show parameter sql_plan_baselines

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_capture_sql_plan_baselines boolean     FALSE
optimizer_use_sql_plan_baselines     boolean     TRUE

啟用自動捕獲SQL執行計劃基線

SQL> alter system set optimizer_capture_sql_plan_baselines=true scope=both sid='*';

System altered.


SQL> create index idx_t1 on t1(c1);

Index created.

SQL> exec dbms_stats.gather_table_stats(ownname=>null,tabname=>'t1',estimate_percent=>100,method_opt=>'for all columns size repeat',cascade=>true);

PL/SQL procedure successfully completed.


SQL> select * from t1 where c1>4076;

924 rows selected.


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

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

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

   1 - filter("C1">4076)

Note
-----
   - SQL plan baseline "SQL_PLAN_6gc99qdv3aa2bdbd90e8e" used for this statement



SQL> select sql_handle, plan_name,origin, enabled, accepted,sql_text  from dba_sql_plan_baselines  where sql_text like 'select %c1>4076';
 
SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENABLED ACCEPTED SQL_TEXT
------------------------------ ------------------------------ -------------- ------- -------- 

--------------------------------------------------------------------------------
SQL_67b129b37635284b           SQL_PLAN_6gc99qdv3aa2bdbd90e8e MANUAL-LOAD    YES     YES      select * from t1 where c1>4076
 

可以看到最佳化器還是使用原來手動建立的SQL執行計劃基線,並沒有生成新的執行計劃,還是執行的全表掃描,並沒有使用我們建立的索引。

禁用SPM,啟用自動捕獲SQL執行計劃基線

SQL> alter system set optimizer_use_sql_plan_baselines=false scope=both sid='*';

System altered.

SQL> select * from t1 where c1>4076;

924 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1369807930

---------------------------------------------------------------------------
| Id  | Operation        | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT |        |   957 |  3828 |     4   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_T1 |   957 |  3828 |     4   (0)| 00:00:01 |
---------------------------------------------------------------------------

可以看到執行計劃使用了對索引idx_t1的範圍掃描,而不是之前的全表掃描了。

SQL> select sql_handle, plan_name,origin, enabled, accepted,sql_text  from dba_sql_plan_baselines  where sql_text like 'select %c1>4076';
 
SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENABLED ACCEPTED SQL_TEXT
------------------------------ ------------------------------ -------------- ------- -------- 

--------------------------------------------------------------------------------
SQL_67b129b37635284b           SQL_PLAN_6gc99qdv3aa2bbeaed07c AUTO-CAPTURE   YES     NO       select * from t1 where c1>4076
SQL_67b129b37635284b           SQL_PLAN_6gc99qdv3aa2bdbd90e8e MANUAL-LOAD    YES     YES      select * from t1 where c1>4076

可以看到ORIGN為AUTO-CAPTURE的SQL執行計劃基線就是自動捕獲的,ENABLED為YES,但是ACCEPTED為NO,這說明雖然建立了新的SQL執行計劃基線但是最佳化器不能使用。下面啟用SPM,看最佳化器是否使用新建立的SQL執行計劃基線。

SQL> alter system set optimizer_use_sql_plan_baselines=true scope=both sid='*';

System altered.

SQL> show parameter sql_plan_baselines

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_capture_sql_plan_baselines boolean     TRUE
optimizer_use_sql_plan_baselines     boolean     TRUE

SQL> select * from t1 where c1>4076;

924 rows selected.


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

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

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

   1 - filter("C1">4076)

Note
-----
   - SQL plan baseline "SQL_PLAN_6gc99qdv3aa2bdbd90e8e" used for this statement

從SQL plan baseline "SQL_PLAN_6gc99qdv3aa2bdbd90e8e" used for this statement資訊可以看到最佳化器還是使用我們手動建立的SQL執行計劃基線,對錶t1執行全表掃描。想要使用執行索引掃描的SQL執行計劃基線就要將其對應的ACCEPTED設定為YES並將使用全表掃描的SQL執行計劃基線的ACCEPTED設定為NO。但是11gr1與11gr2在修改SQL執行計劃基線的ACCEPTED屬性的方法是不同的。另外,一旦在11gr2中將SQL執行計劃基線的ACCEPTED設定為YES,就不能再將其設定為NO。為了不使用某個SQL執行計劃基線,只能將該SQL執行計劃基線的ENABLED設定為NO。

在11gr1中修改SQL執行計劃基線的ACCEPTED屬性值的方法如下:

SQL> DECLARE
  2 x number;
  3  BEGIN
  4  x := dbms_spm.alter_sql_plan_baseline('SQL_67b129b37635284b','SQL_PLAN_6gc99qdv3aa2bbeaed07c',attribute_name=> 'ACCEPTED',attribute_value=> 'YES');
  5  END;
  6  / 
  PL/SQL procedure successfully completed.

如果在11gr2中使用這種方法,將會得到錯誤資訊:

SQL> DECLARE
  2 x number;
  3  BEGIN
  4  x := dbms_spm.alter_sql_plan_baseline('SQL_67b129b37635284b','SQL_PLAN_6gc99qdv3aa2bbeaed07c',attribute_name=> 'ACCEPTED',attribute_value=> 'YES');
  5  END;
  6  / 

ERROR at line 1:
ORA-38136: invalid attribute name ACCEPTED specified
ORA-06512: at "SYS.DBMS_SPM", line 2532
ORA-06512: at line 4

那麼如何在11gr2中修改SQL執行計劃基線的ACCEPTED值,可以使用dbms_spm.evolve_sql_plan_baseline與dbms_spm.alter_sql_plan_baseline。

SQL> SET SERVEROUTPUT ON
SQL> SET LONG 10000
SQL> DECLARE
  2      x clob;
  3  BEGIN
  4      x := dbms_spm.evolve_sql_plan_baseline('SQL_67b129b37635284b', 'SQL_PLAN_6gc99qdv3aa2bbeaed07c',verify=>'NO' ,commit=>'YES');
  5      DBMS_OUTPUT.PUT_LINE(x);
  6  END;
  7  /
-------------------------------------------------------------------------------
                        Evolve SQL Plan Baseline Report
-------------------------------------------------------------------------------

Inputs:
-------
  SQL_HANDLE = SQL_67b129b37635284b
  PLAN_NAME  = SQL_PLAN_6gc99qdv3aa2bbeaed07c
  TIME_LIMIT = DBMS_SPM.AUTO_LIMIT
  VERIFY     = NO
  COMMIT     = YES

Plan: SQL_PLAN_6gc99qdv3aa2bbeaed07c
------------------------------------
  Plan was changed to an accepted plan.

-------------------------------------------------------------------------------
                                 Report Summary
-------------------------------------------------------------------------------
Number of plans verified: 0
Number of plans accepted: 1


PL/SQL procedure successfully completed.

這裡的verify引數在修改ACCEPTED為YES之前是否需要執行相應的執行計劃並與當前可以使用的執行計劃比較效能。如果ACCEPTED為NO的執行計劃的效能有所提高,那麼將執行計劃基線的ACCEPTED設定為YES。當這個引數設定為"YES"時,如果執行計劃的效能有所提高就將ACCEPTED修改為YES。當這個引數設定為"NO"時,直接將ACCEPTED修改為YES。

引數commit指定是否將ACCEPTED值從NO修改為YES。當設定為YES時,執行計劃基線會將ACCEPTED設定為YES並生成一個報告。當設定為NO時,一個報告會生成但不會改變ACCEPTED值。

SQL> select sql_handle, plan_name,origin, enabled, accepted,sql_text  from dba_sql_plan_baselines  where sql_text like 'select %c1>4076';
 
SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENABLED ACCEPTED SQL_TEXT
------------------------------ ------------------------------ -------------- ------- -------- 

--------------------------------------------------------------------------------
SQL_67b129b37635284b           SQL_PLAN_6gc99qdv3aa2bbeaed07c AUTO-CAPTURE   YES     YES      select * from t1 where c1>4076
SQL_67b129b37635284b           SQL_PLAN_6gc99qdv3aa2bdbd90e8e MANUAL-LOAD    YES     YES      select * from t1 where c1>4076
 

SQL> DECLARE
  2      x number;
  3  BEGIN
  4      x := dbms_spm.alter_sql_plan_baseline(sql_handle =>'SQL_67b129b37635284b',plan_name =>'SQL_PLAN_6gc99qdv3aa2bdbd90e8e',attribute_name 

=>'ENABLED',attribute_value =>'NO');
  5  END;
  6  /

PL/SQL procedure successfully completed.

SQL> select sql_handle, plan_name,origin, enabled, accepted,sql_text  from dba_sql_plan_baselines  where sql_text like 'select %c1>4076';
 
SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENABLED ACCEPTED SQL_TEXT
------------------------------ ------------------------------ -------------- ------- -------- 

--------------------------------------------------------------------------------
SQL_67b129b37635284b           SQL_PLAN_6gc99qdv3aa2bbeaed07c AUTO-CAPTURE   YES     YES      select * from t1 where c1>4076
SQL_67b129b37635284b           SQL_PLAN_6gc99qdv3aa2bdbd90e8e MANUAL-LOAD    NO      YES      select * from t1 where c1>4076

現在手動建立的使用全表掃描的SQL執行計劃基線的ENABLED為NO,新生成的使用索引範圍掃描的SQL執行計劃基線的ENABLED與ACCEPTED值為YES,說明最佳化器可以使用。

SQL> select * from t1 where c1>4076;

924 rows selected.


Execution Plan
----------------------------------------------------------
Plan hash value: 1369807930

---------------------------------------------------------------------------
| Id  | Operation        | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT |        |   957 |  3828 |     4   (0)| 00:00:01 |
|*  1 |  INDEX RANGE SCAN| IDX_T1 |   957 |  3828 |     4   (0)| 00:00:01 |
---------------------------------------------------------------------------

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

   1 - access("C1">4076)

Note
-----
   - SQL plan baseline "SQL_PLAN_6gc99qdv3aa2bbeaed07c" used for this statement

可以看到最佳化器確實使用了使用索引範圍掃描的SQL執行計劃基線。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26015009/viewspace-2107763/,如需轉載,請註明出處,否則將追究法律責任。

相關文章