穩定ORACLE的執行計劃

原文發表在:http://l4j.cc/2019/04/19/oracle-sql-plan-management/sql

 不少時候可能咱們都但願CBO可以幫咱們生成正確、高效的執行計劃,可是不少時候事實並不是如此,可能由於各類各樣的緣由(如,統計信息不正確或者CBO天生的缺陷等)都會致使生成的執行計劃特別的低效。以前的一家公司有一臺專門用於批量作數據校驗清洗的數據庫,每次校驗清洗完成數據就會清理掉,統計信息常常會發生較大的變動,以前跑得好好的SQL,可能有時候跑5-6個小時都跑不完了,這時候查看執行計劃,發現不正確的統計信息致使了執行計劃的變動。數據庫

<!-- more -->oracle

 這時候咱們就但願數據庫中運行的SQL都能有正確、穩定的執行計劃,在10g開始的版本中能夠經過SQL Profile來穩定執行計劃或者在不改變SQL的狀況下修改執行計劃。11g開始可使用偏主動的穩定執行計劃的手段——SPM(SQL PLAN MANAGEMENT),保證只有被驗證過的執行計劃纔會被啓用。ide

SQL Profile

 SQL Profile是包含特定於SQL語句的輔助統計信息的數據庫對象,能夠改進優化器基數估計,從而選擇更好的執行計劃。  當選擇執行計劃時優化器會考慮如下信息:函數

  1. SQL Profile提供的輔助統計信息
  2. 當時SQL的運行環境,如數據庫配置,變量綁定,與優化器相關的統計信息等。

 因此,上面兩個條件的任意一個發生變化,都有可能致使執行計劃的改變。下面看下SQL Profile的一些基本操做以及如何在線進行SQL的調整。性能

accepting sql profile

 經過DBMS_SQLTUNE.ACCEPT_SQL_PROFILE存儲過程能夠接受一個SQL Profile,只有在咱們接受了一個SQL Profile以後,優化器才能使用他做爲產生執行計劃的輸入。這個存儲過程有兩個比較重要的參數:測試

  • profile_type 這個參數用於控制是否改變並行執行行爲,REGULAR_PROFILE 不更改成並行執行,PX_PROFLE 用於更改並行執行的SQL Profile。
  • force_match 該參數用於控制SQL語句匹配,有兩個值——TRUE和FALSE。對於SQL語句中where條件的字面值,當force_match=TRUE時,會將其替換爲變量綁定,因此當字面值不一樣時也能夠重用該SQL Profile。值爲FALSE時,where條件的字面值則不會替換。

下面是ACCEPT_SQL_PROFILE的例子:優化

DECLARE
  my_sqlprofile_name VARCHAR2(30);
BEGIN
  my_sqlprofile_name := DBMS_SQLTUNE.ACCEPT_SQL_PROFILE ( 
    task_name    => 'STA_SPECIFIC_EMP_TASK'
,   name         => 'my_sql_profile'
,   profile_type => DBMS_SQLTUNE.PX_PROFILE
,   force_match  => true 
);
END;
/

Listing SQL Profile

 能夠經過DBA_SQL_PROFILES數據字典視圖來查看存儲在數據庫中的SQL Profile。this

SQL> SELECT NAME,CATEGORY,SQL_TEXT,FORCE_MATCHING,STATUS FROM DBA_SQL_PROFILES;

NAME                           CATEGORY   SQL_TEXT                  FOR STATUS
------------------------------ ---------- ------------------------- --- --------
SYS_SQLPROF_016986bccd640000   DEFAULT    select /*+ use_nl(a b) in NO  ENABLED
                                          dex(b) */a.brwyid,a.yljgd
                                          m,a.jzlsh,b.mzzddm from t
                                          est_e

Altering SQL Profile

 經過ALTER_SQL_PROFILE中的attribute_name參數能夠修改SQL Profile相應的參數值。調試

BEGIN DBMS_SQLTUNE.ALTER_SQL_PROFILE ( 
   name            =>  'my_sql_profile'
,  attribute_name  =>  'FORCE_MATCH'
,  value           =>  'TRUE'      
);
END;
/

Droping SQL Profile

 經過DROP_SQL_PROFILE存儲過程能夠刪除特定的SQL Profile

BEGIN
  DBMS_SQLTUNE.DROP_SQL_PROFILE ( 
    name => 'my_sql_profile' 
);
END;
/

經過SQL Profile調整線上SQL執行計劃

 經過手工建立SQL Profile的方式,能夠在不更改目標SQL的SQL文本的狀況下修改SQL的執行計劃,並且能夠很好的穩定SQL的執行計劃。  下面是手工建立SQL Profile的例子,在TEST_ENV.TB_TABLE_LIST的列TABLE_NAME上有一個名爲IDX_TB_TABLE_LIST_TBNAME的B樹索引: 一、首先加一個全表掃描的HINTS來執行下面的SQL,模擬線上的一個執行低效的SQL,並查看其執行計劃。

SQL> SELECT /*+FULL(T)*/ TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

TABLE_NAME
------------------------------
ACCESS$

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'advanced'));

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID  1a319c1c2b3rz, child number 0
-------------------------------------
SELECT /*+FULL(T)*/ TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE
TABLE_NAME='ACCESS$'

Plan hash value: 1475094007

-----------------------------------------------------------------------------------
| Id  | Operation         | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |               |       |       |    31 (100)|          |

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
|*  1 |  TABLE ACCESS FULL| TB_TABLE_LIST |     1 |    18 |    31   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1 / T@SEL$1

Outline Data
-------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('18.1.0')
      DB_VERSION('18.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      FULL(@"SEL$1" "T"@"SEL$1")
      END_OUTLINE_DATA
  */


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

   1 - filter("TABLE_NAME"='ACCESS$')

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (rowset=256) "TABLE_NAME"[VARCHAR2,128]


已選擇 43 行。

二、而後加入走索引的HINTS來更正這個SQL的執行計劃,獲得下面的執行計劃相關信息,此時咱們就須要用這個執行計劃來替換掉上面走全表掃描的SQL的執行計劃。

SQL> SELECT /*+ INDEX(T IDX_TB_TABLE_LIST_TBNAME) */TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';


TABLE_NAME
------------------------------
ACCESS$

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'advanced'));

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID  44j1ysb93cwdq, child number 0
-------------------------------------
SELECT /*+ INDEX(T IDX_TB_TABLE_LIST_TBNAME) */TABLE_NAME FROM
TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$'

Plan hash value: 3318876060

---------------------------------------------------------------------------------------------
| Id  | Operation        | Name                     | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                          |       |       |     1 (100)|          |

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
|*  1 |  INDEX RANGE SCAN| IDX_TB_TABLE_LIST_TBNAME |     1 |    18 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1 / T@SEL$1

Outline Data
-------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('18.1.0')
      DB_VERSION('18.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      INDEX(@"SEL$1" "T"@"SEL$1" ("TB_TABLE_LIST"."TABLE_NAME"))
      END_OUTLINE_DATA
  */


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

   1 - access("TABLE_NAME"='ACCESS$')

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "TABLE_NAME"[VARCHAR2,128]


已選擇 43 行。

三、下面查看對應的SQL_ID。

SQL> SELECT SQL_TEXT,SQL_ID FROM V$SQLAREA WHERE SQL_TEXT LIKE '%TABLE_NAME FROM TEST_ENV.TB_TABLE%';

SQL_TEXT                  SQL_ID
------------------------- -------------
SELECT /*+ INDEX(T IDX_TB 44j1ysb93cwdq
_TABLE_LIST_TBNAME) */TAB
LE_NAME FROM TEST_ENV.TB_
TABLE_LIST T WHERE TABLE_
NAME='ACCESS$'

SELECT SQL_TEXT,SQL_ID FR g4v1sg4ycf96y
OM V$SQLAREA WHERE SQL_TE
XT LIKE '%TABLE_NAME FROM
 TEST_ENV.TB_TABLE%'


SQL_TEXT                  SQL_ID
------------------------- -------------
SELECT /*+FULL(T)*/ TABLE 1a319c1c2b3rz
_NAME FROM TEST_ENV.TB_TA
BLE_LIST T WHERE TABLE_NA
ME='ACCESS$'

四、建立SQL PROFILE,用正確的執行計劃的OUT LINE DATA來建立SQL Profile

SQL> declare
  2     v_hints sys.sqlprof_attr;
  3     clsql_text clob;
  4  begin
  5     v_hints := sys.sqlprof_attr('BEGIN_OUTLINE_DATA',
  6        'IGNORE_OPTIM_EMBEDDED_HINTS',
  7        'OPTIMIZER_FEATURES_ENABLE(''18.1.0'')',
  8        'DB_VERSION(''18.1.0'')',
  9        'ALL_ROWS',
 10        'OUTLINE_LEAF(@"SEL$1")',
 11        'INDEX(@"SEL$1" "T"@"SEL$1" ("TB_TABLE_LIST"."TABLE_NAME"))',
 12        'END_OUTLINE_DATA');
 13
 14      select sql_fulltext into clsql_text from v$sqlarea where sql_id='1a319c1c2b3rz';
 15
 16      dbms_sqltune.import_sql_profile(clsql_text,v_hints,'my_sql_profile',force_match=>true,replace=>true);
 17  end;
 18  /

PL/SQL 過程已成功完成。

五、最後再來看加FULL這個HINTS的SQL語句的執行計劃,能夠看到此時已是作的索引範圍掃描了。

SQL> SELECT /*+FULL(T)*/ TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

TABLE_NAME
------------------------------
ACCESS$

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'advanced'));

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID  1a319c1c2b3rz, child number 0
-------------------------------------
SELECT /*+FULL(T)*/ TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE
TABLE_NAME='ACCESS$'

Plan hash value: 3318876060

---------------------------------------------------------------------------------------------
| Id  | Operation        | Name                     | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                          |       |       |     1 (100)|          |

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
|*  1 |  INDEX RANGE SCAN| IDX_TB_TABLE_LIST_TBNAME |     1 |    18 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1 / T@SEL$1

Outline Data
-------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('18.1.0')
      DB_VERSION('18.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      INDEX(@"SEL$1" "T"@"SEL$1" ("TB_TABLE_LIST"."TABLE_NAME"))
      END_OUTLINE_DATA
  */


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

   1 - access("TABLE_NAME"='ACCESS$')

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "TABLE_NAME"[VARCHAR2,128]

Note

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
-----
   - SQL profile my_sql_profile used for this statement


已選擇 47 行。

SPM

 SQL Plan Management(SPM)能夠有效避免執行計劃變動而致使的性能降低的問題,只有被驗證和接受的執行計劃纔是可用的。SPM採用了一種叫SQL PLAN BASELINE的機制,它是一系列被驗證性能良好的SQL執行計劃的集合。無論SQL Plan Baseline仍是SQL Profile都是經過內部使用hints來實現的,他們之間的區別以下:

  1. SQL Plan BaseLine是一種偏主動的機制,能夠在性能問題出現以前就建立SQL基線,避免優化器在將來某個時刻選擇次優的執行計劃。而SQL Profile只能等到發現SQL的性能問題時,調用SQL Tuning Advisor來對有問題的SQL進行調整。
  2. SQL Plan Baseline會重新產生一個具體的執行計劃,不會隨着其餘相關統計信息的變動而變動,可是SQL Profile只是爲優化器提供一個輔助信息。 SQL Plan Baseline的hints會指定生成一個具體的執行計劃,可是SQL Profile的hints只是幫助調整優化器錯誤的計算

初始化參數配置

 能夠經過如下兩個參數來控制SPM的行爲:

  • OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES=TRUE|FALSE 該參數用於控制是否啓用自動捕獲SQL Plan Baseline,默認值爲FALSE。該參數能夠在SESSION或者SYSTEM級別進行修改,修改成TRUE後,ORACLE會對其影響的範圍內的全部重複執行的SQL自動捕獲其SQL Plan Baseline。對於第一次捕獲到的結果,其ENABLED和ACCEPTED的值均爲'YES'。當執行計劃變動,被再次捕獲到時,其ENABLED=YES可是ACCEPTED的值爲'NO',表示該SQL依然會使用第一次捕獲到的SQL執行計劃。
  • OPTIMIZER_USE_SQL_PLAN_BASELINES=TRUE|FALSE 該參數用於控制是否啓用SQL Plan Baseline,默認值爲TRUE,該參數也能夠在SESSION和SYSTEM級別設置。

查看SQL Plan Baseline中的執行計劃

 經過數據字典DBA_SQL_PLAN_BASELINES能夠查詢到存儲在數據庫中的SQL Plan Baselines,而後使用DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE函數能夠查看對應的執行計劃。

SELECT SIGNATURE,SQL_TEXT,SQL_HANDLE,PLAN_NAME FROM DBA_SQL_PLAN_BASELINES;

SELECT * from table(DBMS_XPLAN.DISPLAY_SQL_PLAN_BASELINE('SQL_787830cec4402bdf','SQL_PLAN_7hy1htv240ayz01f095c0','advanced'));

批量加載SQL Plan Baseline

 經過DBMS_SPM包提供的相關函數,咱們能夠從SQL Tuning Set、 Shared SQL Area和Staging Table中加載SQL Plan Baseline。比較經常使用的是經過Staging Table的方式來進行不一樣數據庫之間SQL Plan Baseline的遷移,好比咱們在測試庫中調試好了一批SQL,須要將其執行計劃導入到生產庫中。  下面是經過Staging Table方式將A庫的SQL Plan Baseline遷移到B庫的基本流程:

  1. 使用DBMS_SPM.CREATE_STGTAB_BASELINE建立中間表。
BEGIN
  DBMS_SPM.CREATE_STGTAB_BASELINE (
    table_name => 'stage1');
END;
/
  1. 將SQL Plan Baseline打包到剛剛建立的中間表stage1
DECLARE
  v_plan_cnt NUMBER;
BEGIN
  v_plan_cnt := DBMS_SPM.PACK_STGTAB_BASELINE (
    table_name => 'stage1'
,   enabled    => 'yes'
,   creator    => 'spm'
);
END;
/
  1. 將中間表傳輸到目標數據庫中,能夠經過數據泵等手段。
  2. 在目標庫中,將中間表的數據解壓。
DECLARE
  v_plan_cnt NUMBER;
BEGIN
  v_plan_cnt := DBMS_SPM.UNPACK_STGTAB_BASELINE (
    table_name => 'stage1'
,   fixed      => 'yes'
);
END;
/

刪除SQL Plan Baseline

 經過DBMS_SPM.DROP_SQL_PLAN_BASELINE函數能夠刪除已經保存的SQL Plan Baseline:

  1. 首先經過DBA_SQL_PLAN_BASELINES獲取到對應的SQL_HANDLE
  2. 執行刪除操做
SQL> EXEC DBMS_SPM.DROP_SQL_PLAN_BASELINE (sql_handle => 'SQL_b6b0d1c71cd1807b');

實例1——自動捕獲

  1. 修改optimizer_capture_sql_plan_baselines參數啓用自動捕獲
SQL> alter system flush shared_pool;

系統已更改。

SQL> alter system flush buffer_cache;

系統已更改。

SQL> show parameter sql_plan

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_capture_sql_plan_baselines boolean     FALSE
optimizer_use_sql_plan_baselines     boolean     TRUE
SQL> alter system set optimizer_capture_sql_plan_baselines=TRUE;

系統已更改。

SQL> show parameter sql_pla

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_capture_sql_plan_baselines boolean     TRUE
optimizer_use_sql_plan_baselines     boolean     TRUE
  1. 第一次執行SQL,能夠看到在DBA_SQL_PLAN_BASELINES中並未查到相應的SQL基線,再次執行才能查詢到。
SQL> SET PAGES 10000 LINES 140
SQL> SET SERVEROUTPUT ON
SQL> COL SQL_TEXT FOR A20
SQL> COL SQL_HANDLE FOR A20
SQL> COL PLAN_NAME FOR A30
SQL> COL ORIGIN FOR A12
SQL> COL TABLE_NAME FOR A20
SQL> SET LONGC 60535
SQL> SET LONG 60535
SQL> SET ECHO ON
SQL> SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

TABLE_NAME
--------------------
ACCESS$

SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED, FIXED, AUTOPURGE FROM   DBA_SQL_PLAN_BASELINES W
HERE  SQL_TEXT LIKE '%TEST_ENV.TB_TABLE_LIST%';

未選定行
  1. 再次執行上面的SQL。查詢DBA_SQL_PLAN_BASELINES,對應的SQL Plan Baseline的ACCEPTED和ENABLE的值均爲YES。
SQL> SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

TABLE_NAME
--------------------
ACCESS$

SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED, FIXED, AUTOPURGE FROM   DBA_SQL_PLAN_BASELINES W
HERE  SQL_TEXT LIKE '%TEST_ENV.TB_TABLE_LIST%';

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN       ENA ACC FIX AUT
-------------------- -------------------- ------------------------------ ------------ --- --- --- ---
SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayzc127edb7 AUTO-CAPTURE YES YES NO  YES
                     OM TEST_ENV.TB_TABLE
                     _LIST T WHERE TABLE_
                     NAME='ACCESS$'
  1. 在表上建立一個TABLE_NAME列的B-TREE索引,而後再次執行上面的SQL語句,經過DBA_SQL_PLAN_BASELINES查詢,此時多了一條SQL Plan Baseline,ENABLE=YES,ACCEPTED=NO
SQL> CREATE INDEX test_env.IDX_TB_TABLE_LIST_TBNAME ON TEST_ENV.TB_TABLE_LIST(TABLE_NAME);

索引已建立。

SQL> EXEC DBMS_STATS.GATHER_TABLE_STATS('TEST_ENV','TB_TABLE_LIST',CASCADE=>TRUE);

PL/SQL 過程已成功完成。

SQL> SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

TABLE_NAME
--------------------
ACCESS$

SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED, FIXED, AUTOPURGE FROM   DBA_SQL_PLAN_BASELINES W
HERE  SQL_TEXT LIKE '%TEST_ENV.TB_TABLE_LIST%';

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN       ENA ACC FIX AUT
-------------------- -------------------- ------------------------------ ------------ --- --- --- ---
SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayz01f095c0 AUTO-CAPTURE YES NO  NO  YES
                     OM TEST_ENV.TB_TABLE
                     _LIST T WHERE TABLE_
                     NAME='ACCESS$'

SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayzc127edb7 AUTO-CAPTURE YES YES NO  YES
                     OM TEST_ENV.TB_TABLE
                     _LIST T WHERE TABLE_
                     NAME='ACCESS$'
  1. 在TABLE_NAME列建立索引以後,根據此列查詢,應該是走INDEX RANGE SCAN,可是事實是怎麼樣呢?看下該語句的執行計劃。
SQL> explain plan for SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

已解釋。

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(null, null, 'basic +note'));

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
--------------------
Plan hash value: 1475094007

-------------------------------------------
| Id  | Operation         | Name          |
-------------------------------------------
|   0 | SELECT STATEMENT  |               |
|   1 |  TABLE ACCESS FULL| TB_TABLE_LIST |
-------------------------------------------

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

已選擇 12 行。

 能夠看到,執行這個SQL依然走的是全表掃描,注意note部分,表示這個執行計劃使用了"SQL_PLAN_7hy1htv240ayzc127edb7"的SQL Plan Baseline。代表了SPM能夠很好的固定特定SQL的執行計劃。 6. 可是實際上此時應該是走索引範圍掃描纔是最高效的,即"SQL_PLAN_7hy1htv240ayz01f095c0"這個SQL Plan Baseline,如何啓用改baseline呢?首先建立一個evole任務,並執行該任務。

SQL> var cnt NUMBER
SQL> var tk_name VARCHAR2(50)
SQL> var exe_name VARCHAR2(50)
SQL> var evol_out CLOB
SQL> EXEC :tk_name := DBMS_SPM.CREATE_EVOLVE_TASK(sql_handle => 'SQL_787830cec4402bdf', plan_name  => 'SQL_PLAN_7hy1htv2
40ayz01f095c0');

PL/SQL 過程已成功完成。

SQL> print :tk_name

TK_NAME
--------
任務_31

SQL> EXEC :exe_name :=DBMS_SPM.EXECUTE_EVOLVE_TASK(task_name=>:tk_name);

PL/SQL 過程已成功完成。

SQL> print :exe_name

EXE_NAME
--------
EXEC_151
  1. 執行完成以後,經過REPORT_EVOLVE_TASK能夠查看到相應的任務報告。Findings部分告訴咱們發現了一個比基線效率更高的執行計劃,並提供了建議方案。
SQL> EXEC :evol_out := DBMS_SPM.REPORT_EVOLVE_TASK( task_name=>:tk_name, execution_name=>:exe_name );

PL/SQL 過程已成功完成。

SQL> SELECT :evol_out FROM DUAL;

:EVOL_OUT
------------------------------------------------------------------------------------------------------------------------
--------------------
GENERAL INFORMATION SECTION
---------------------------------------------------------------------------------------------

 Task Information:
 ---------------------------------------------
 Task Name            : 任務_31
 Task Owner           : SYS
 Execution Name       : EXEC_151
 Execution Type       : SPM EVOLVE
 Scope                : COMPREHENSIVE
 Status               : COMPLETED
 Started              : 04/19/2019 16:45:33
 Finished             : 04/19/2019 16:45:33
 Last Updated         : 04/19/2019 16:45:33
 Global Time Limit    : 2147483646
 Per-Plan Time Limit  : UNUSED
 Number of Errors     : 0
---------------------------------------------------------------------------------------------

SUMMARY SECTION
---------------------------------------------------------------------------------------------
  Number of plans processed  : 1
  Number of findings         : 1
  Number of recommendations  : 1
  Number of errors           : 0
---------------------------------------------------------------------------------------------

DETAILS SECTION
---------------------------------------------------------------------------------------------
 Object ID          : 2
 Test Plan Name     : SQL_PLAN_7hy1htv240ayz01f095c0
 Base Plan Name     : SQL_PLAN_7hy1htv240ayzc127edb7
 SQL Handle         : SQL_787830cec4402bdf
 Parsing Schema     : SYS
 Test Plan Creator  : SYS
 SQL Text           : SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE
                    TABLE_NAME='ACCESS$'

Execution Statistics:
-----------------------------
                    Base Plan                     Test Plan
                    ----------------------------  ----------------------------
 Elapsed Time (s):  .000016                       .000001
 CPU Time (s):      0                             0
 Buffer Gets:       10                            0
 Optimizer Cost:    31                            1
 Disk Reads:        0                             0
 Direct Writes:     0                             0
 Rows Processed:    0                             0
 Executions:        10                            10


FINDINGS SECTION
---------------------------------------------------------------------------------------------

Findings (1):
-----------------------------
 1. 計劃已在 0.03200 秒內驗證完畢。此計劃符合收益標準, 這是由於其驗證性能比基線計劃的性能高 50.50000 倍。

Recommendation:
-----------------------------
 Consider accepting the plan. Execute
 dbms_spm.accept_sql_plan_baseline(task_name => '任務_31', object_id => 2,
 task_owner => 'SYS');


EXPLAIN PLANS SECTION
---------------------------------------------------------------------------------------------

Baseline Plan
-----------------------------
 Plan Id          : 201
 Plan Hash Value  : 3240619447

------------------------------------------------------------------------------
| Id  | Operation           | Name          | Rows | Bytes | Cost | Time     |
------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |               |    1 |    18 |   31 | 00:00:01 |
| * 1 |   TABLE ACCESS FULL | TB_TABLE_LIST |    1 |    18 |   31 | 00:00:01 |
------------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 1 - filter("TABLE_NAME"='ACCESS$')


Test Plan
-----------------------------
 Plan Id          : 202
 Plan Hash Value  : 32544192

----------------------------------------------------------------------------------------
| Id  | Operation          | Name                     | Rows | Bytes | Cost | Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |                          |    1 |    18 |    1 | 00:00:01 |
| * 1 |   INDEX RANGE SCAN | IDX_TB_TABLE_LIST_TBNAME |    1 |    18 |    1 | 00:00:01 |
----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
------------------------------------------
* 1 - access("TABLE_NAME"='ACCESS$')

---------------------------------------------------------------------------------------------
  1. 能夠經過上面報告中建議的方式來接受這個計劃,也可使用IMPLEMENT_EVOLVE_TASK函數。
SQL> EXEC :cnt := DBMS_SPM.IMPLEMENT_EVOLVE_TASK( task_name=>:tk_name, execution_name=>:exe_name );

PL/SQL 過程已成功完成。

SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED FROM   DBA_SQL_PLAN_BASELINES WHERE  SQL_HANDLE='
SQL_787830cec4402bdf';

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN       ENA ACC
-------------------- -------------------- ------------------------------ ------------ --- ---
SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayz01f095c0 AUTO-CAPTURE YES YES
                     OM TEST_ENV.TB_TABLE
                     _LIST T WHERE TABLE_
                     NAME='ACCESS$'

SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayzc127edb7 AUTO-CAPTURE YES YES
                     OM TEST_ENV.TB_TABLE
                     _LIST T WHERE TABLE_
                     NAME='ACCESS$'
  1. 最後咱們再來看下執行計劃
SQL> explain plan for SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

已解釋。

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(null, null, 'basic +note'));

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------
Plan hash value: 3318876060

-----------------------------------------------------
| Id  | Operation        | Name                     |
-----------------------------------------------------
|   0 | SELECT STATEMENT |                          |
|   1 |  INDEX RANGE SCAN| IDX_TB_TABLE_LIST_TBNAME |
-----------------------------------------------------

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

已選擇 12 行。

 能夠看到此時已經走了索引範圍掃描,使用的是"SQL_PLAN_7hy1htv240ayz01f095c0"這個SQL Plan Baseline。當存在多個計劃的ACCEPTED和ENABLE的值都爲YES的時候,優化器會選擇一個成本更低的計劃來執行。

實例2——手工生成

 接下來看下手工生成SQL Plan Baseline的方法。其實很是簡單,核心就是經過DBMS_STATS.LOAD_PLANS_FROM_CURSOR_CACHE來從Shared SQL Area中加載執行計劃。

  1. 首先對前面例子生成的內容進行清理。
SQL> alter system set optimizer_capture_sql_plan_baselines=false;

系統已更改。

SQL> show parameter sql_pla

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

SQL> EXEC :cnt :=DBMS_SPM.DROP_SQL_PLAN_BASELINE('SQL_787830cec4402bdf');

PL/SQL 過程已成功完成。

SQL> EXEC :cnt :=DBMS_SPM.DROP_SQL_PLAN_BASELINE('SQL_061becb140fad607');

PL/SQL 過程已成功完成。

SQL> EXEC :cnt :=DBMS_SPM.DROP_SQL_PLAN_BASELINE('SQL_ecca2815c7166fb6');

PL/SQL 過程已成功完成。

SQL> EXEC :cnt :=DBMS_SPM.DROP_SQL_PLAN_BASELINE('SQL_9049245213a986b3');

PL/SQL 過程已成功完成。

SQL> EXEC :cnt :=DBMS_SPM.DROP_SQL_PLAN_BASELINE('SQL_85372e07e425b213');

PL/SQL 過程已成功完成。

SQL> DELETE FROM SQLLOG$;

已刪除 9 行。

SQL> commit;

提交完成。

SQL> alter system flush shared_pool;

系統已更改。

SQL> alter system flush buffer_cache;

系統已更改。
  1. 執行SQL並查看執行計劃
SQL> SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

TABLE_NAME
--------------------
ACCESS$

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'advanced'));

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

SQL_ID  drmkgq2ppg7kg, child number 0
-------------------------------------
SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE
TABLE_NAME='ACCESS$'

Plan hash value: 1475094007

-----------------------------------------------------------------------------------
| Id  | Operation         | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |               |       |       |    31 (100)|          |

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

|*  1 |  TABLE ACCESS FULL| TB_TABLE_LIST |     1 |    18 |    31   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1 / T@SEL$1

Outline Data
-------------


PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('18.1.0')
      DB_VERSION('18.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      FULL(@"SEL$1" "T"@"SEL$1")
      END_OUTLINE_DATA
  */


PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

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

   1 - filter("TABLE_NAME"='ACCESS$')

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (rowset=256) "TABLE_NAME"[VARCHAR2,128]


已選擇 43 行。
  1. 由於此時自動捕獲是關閉的,因此無論執行多少次SQL,都沒有對應的SQL Plan Baseline。能夠手動的將對應的執行計劃加入到SQL Plan Baseline中。
SQL> var cnt number
SQL> exec :cnt := DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE(sql_id=>'drmkgq2ppg7kg', plan_hash_value=>'1475094007');

PL/SQL 過程已成功完成。

SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED FROM   DBA_SQL_PLAN_BASELINES WHERE SQL_TEXT LIKE '%TEST_ENV.TB_TABLE_LIST%';

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN       ENA ACC
-------------------- -------------------- ------------------------------ ------------ --- ---
SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayzc127edb7 MANUAL-LOAD- YES YES
                     OM TEST_ENV.TB_TABLE                                FROM-CURSOR-
                     _LIST T WHERE TABLE_                                CACHE
                     NAME='ACCESS$'
  1. 在TABLE_NAME列上建立索引,而後再次執行SQL,並查看執行計劃。能夠看到雖然在TABLE_NAME這個列上存在索引,可是已經存在對應SQL語句的一個走全表掃描的執行基線,因此此時依舊走的全表掃描,使用的是剛剛加載進去的'SQL_PLAN_7hy1htv240ayzc127edb7'這個SQL Plan Baseline。
SQL> SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

TABLE_NAME
--------------------
ACCESS$

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'advanced'));

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------

SQL_ID  drmkgq2ppg7kg, child number 1
-------------------------------------
SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE
TABLE_NAME='ACCESS$'

Plan hash value: 1475094007

-----------------------------------------------------------------------------------
| Id  | Operation         | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |               |       |       |    31 (100)|          |

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------

|*  1 |  TABLE ACCESS FULL| TB_TABLE_LIST |     1 |    18 |    31   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1 / T@SEL$1

Outline Data
-------------


PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------

  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('18.1.0')
      DB_VERSION('18.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      FULL(@"SEL$1" "T"@"SEL$1")
      END_OUTLINE_DATA
  */


PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------

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

   1 - filter("TABLE_NAME"='ACCESS$')

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (rowset=256) "TABLE_NAME"[VARCHAR2,128]

Note

PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------------------------------

-----
   - SQL plan baseline SQL_PLAN_7hy1htv240ayzc127edb7 used for this statement


已選擇 47 行。
  1. 這個時候咱們再來查看下DBA_SQL_PLAN_BASELINES這個數據字典,能夠看到SPM幫咱們自動捕獲了一條ENABLE爲YES,ACCEPTED爲NO的SQL Plan Baseline。
SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED FROM   DBA_SQL_PLAN_BASELINES WHERE SQL_TEXT LIKE
 '%TEST_ENV.TB_TABLE_LIST%';

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN       ENA ACC
-------------------- -------------------- ------------------------------ ------------ --- ---
SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayz01f095c0 AUTO-CAPTURE YES NO
                     OM TEST_ENV.TB_TABLE
                     _LIST T WHERE TABLE_
                     NAME='ACCESS$'

SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayzc127edb7 MANUAL-LOAD- YES YES
                     OM TEST_ENV.TB_TABLE                                FROM-CURSOR-
                     _LIST T WHERE TABLE_                                CACHE
                     NAME='ACCESS$'
  1. 將'SQL_PLAN_7hy1htv240ayz01f095c0'的ACCEPTED的值改成YES。
SQL> var result clob;
SQL> EXEC :result :=DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE(SQL_HANDLE=>'SQL_787830cec4402bdf', PLAN_NAME=>'SQL_PLAN_7hy1htv24
0ayz01f095c0', VERIFY=>'NO', COMMIT=>'YES');

PL/SQL 過程已成功完成。

SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED FROM   DBA_SQL_PLAN_BASELINES WHERE SQL_TEXT LIKE
 '%TEST_ENV.TB_TABLE_LIST%';

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN       ENA ACC
-------------------- -------------------- ------------------------------ ------------ --- ---
SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayz01f095c0 AUTO-CAPTURE YES YES
                     OM TEST_ENV.TB_TABLE
                     _LIST T WHERE TABLE_
                     NAME='ACCESS$'

SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayzc127edb7 MANUAL-LOAD- YES YES
                     OM TEST_ENV.TB_TABLE                                FROM-CURSOR-
                     _LIST T WHERE TABLE_                                CACHE
                     NAME='ACCESS$'
  1. 再次執行SQL,此時使用了'SQL_PLAN_7hy1htv240ayz01f095c0'這個SQL Plan Baseline了。
SQL> SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

TABLE_NAME
--------------------
ACCESS$

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'advanced'));

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

SQL_ID  drmkgq2ppg7kg, child number 0
-------------------------------------
SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE
TABLE_NAME='ACCESS$'

Plan hash value: 3318876060

---------------------------------------------------------------------------------------------
| Id  | Operation        | Name                     | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |                          |       |       |     1 (100)|          |

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

|*  1 |  INDEX RANGE SCAN| IDX_TB_TABLE_LIST_TBNAME |     1 |    18 |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1 / T@SEL$1

Outline Data
-------------


PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('18.1.0')
      DB_VERSION('18.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      INDEX(@"SEL$1" "T"@"SEL$1" ("TB_TABLE_LIST"."TABLE_NAME"))
      END_OUTLINE_DATA
  */


PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

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

   1 - access("TABLE_NAME"='ACCESS$')

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - "TABLE_NAME"[VARCHAR2,128]

Note

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

-----
   - SQL plan baseline SQL_PLAN_7hy1htv240ayz01f095c0 used for this statement


已選擇 47 行。
  1. 前面的SQL都是沒有HINTS的,有時候咱們需加入HINTS對SQL的執行計劃進行調整。如何用加入了hints的SQL執行計劃來替換以前的SQL,生成新的SQL Plan Baseline呢?首先刪除以前作全表掃描的SQL Plan Baseline,而後加入一個FULL的hints來執行SQL,此時SQL_ID和以前是不一樣的。
SQL> exec :cnt :=DBMS_SPM.DROP_SQL_PLAN_BASELINE (sql_handle=>'SQL_787830cec4402bdf', plan_name=>'SQL_PLAN_7hy1htv240ayz
c127edb7');

PL/SQL 過程已成功完成。

SQL> SELECT /*+FULL(T)*/ TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

TABLE_NAME
--------------------
ACCESS$

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'advanced'));

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------

SQL_ID  1a319c1c2b3rz, child number 0
-------------------------------------
SELECT /*+FULL(T)*/ TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE
TABLE_NAME='ACCESS$'

Plan hash value: 1475094007

-----------------------------------------------------------------------------------
| Id  | Operation         | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |               |       |       |    31 (100)|          |

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------

|*  1 |  TABLE ACCESS FULL| TB_TABLE_LIST |     1 |    18 |    31   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1 / T@SEL$1

Outline Data
-------------


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------

  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('18.1.0')
      DB_VERSION('18.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      FULL(@"SEL$1" "T"@"SEL$1")
      END_OUTLINE_DATA
  */


PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------------------------

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

   1 - filter("TABLE_NAME"='ACCESS$')

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (rowset=256) "TABLE_NAME"[VARCHAR2,128]


已選擇 43 行。

 此時從索引範圍掃描變成了全表掃描,SQL_ID爲1a319c1c2b3rz,PLAN_HASH_VALUE爲1475094007 9. 此時的DBA_SQL_PLAN_BASELINES依然以後剛剛那一條記錄。

SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED FROM   DBA_SQL_PLAN_BASELINES WHERE SQL_TEXT LIKE
 '%TEST_ENV.TB_TABLE_LIST%';

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN       ENA ACC
-------------------- -------------------- ------------------------------ ------------ --- ---
SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayz01f095c0 AUTO-CAPTURE YES YES
                     OM TEST_ENV.TB_TABLE
                     _LIST T WHERE TABLE_
                     NAME='ACCESS$'
  1. 如今用上述改寫後的SQL的新的執行計劃來手工生成SQL Plan Baseline
SQL> exec :cnt := dbms_spm.load_plans_from_cursor_cache(sql_id => '1a319c1c2b3rz', plan_hash_value=>1475094007, sql_handle=>'SQL_787830cec4402bdf')

PL/SQL 過程已成功完成。

SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED FROM   DBA_SQL_PLAN_BASELINES WHERE SQL_TEXT LIKE
 '%TEST_ENV.TB_TABLE_LIST%';

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN       ENA ACC
-------------------- -------------------- ------------------------------ ------------ --- ---
SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayz01f095c0 AUTO-CAPTURE YES YES
                     OM TEST_ENV.TB_TABLE
                     _LIST T WHERE TABLE_
                     NAME='ACCESS$'

SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayzc127edb7 MANUAL-LOAD- YES YES
                     OM TEST_ENV.TB_TABLE                                FROM-CURSOR-
                     _LIST T WHERE TABLE_                                CACHE
                     NAME='ACCESS$'
  1. 因爲此時所對應的SQL Plan Baseline的ENABLED和ACCEPTED的值都爲YES,咱們將以前的走索引範圍掃描的ENABLED屬性改成NO,而後執行SQL語句。
SQL> EXEC :CNT := DBMS_SPM.ALTER_SQL_PLAN_BASELINE(SQL_HANDLE=>'SQL_787830cec4402bdf', PLAN_NAME=>'SQL_PLAN_7hy1htv240ay
z01f095c0', ATTRIBUTE_NAME=>'ENABLED', ATTRIBUTE_VALUE=>'NO');

PL/SQL 過程已成功完成。

SQL> SELECT SQL_HANDLE, SQL_TEXT, PLAN_NAME, ORIGIN, ENABLED, ACCEPTED FROM   DBA_SQL_PLAN_BASELINES WHERE SQL_TEXT LIKE
 '%TEST_ENV.TB_TABLE_LIST%';

SQL_HANDLE           SQL_TEXT             PLAN_NAME                      ORIGIN       ENA ACC
-------------------- -------------------- ------------------------------ ------------ --- ---
SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayz01f095c0 AUTO-CAPTURE NO  YES
                     OM TEST_ENV.TB_TABLE
                     _LIST T WHERE TABLE_
                     NAME='ACCESS$'

SQL_787830cec4402bdf SELECT TABLE_NAME FR SQL_PLAN_7hy1htv240ayzc127edb7 MANUAL-LOAD- YES YES
                     OM TEST_ENV.TB_TABLE                                FROM-CURSOR-
                     _LIST T WHERE TABLE_                                CACHE
                     NAME='ACCESS$'

SQL> SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE TABLE_NAME='ACCESS$';

TABLE_NAME
--------------------
ACCESS$

SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'advanced'));

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

SQL_ID  drmkgq2ppg7kg, child number 1
-------------------------------------
SELECT TABLE_NAME FROM TEST_ENV.TB_TABLE_LIST T WHERE
TABLE_NAME='ACCESS$'

Plan hash value: 1475094007

-----------------------------------------------------------------------------------
| Id  | Operation         | Name          | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |               |       |       |    31 (100)|          |

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

|*  1 |  TABLE ACCESS FULL| TB_TABLE_LIST |     1 |    18 |    31   (0)| 00:00:01 |
-----------------------------------------------------------------------------------

Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------

   1 - SEL$1 / T@SEL$1

Outline Data
-------------


PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

  /*+
      BEGIN_OUTLINE_DATA
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('18.1.0')
      DB_VERSION('18.1.0')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$1")
      FULL(@"SEL$1" "T"@"SEL$1")
      END_OUTLINE_DATA
  */


PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

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

   1 - filter("TABLE_NAME"='ACCESS$')

Column Projection Information (identified by operation id):
-----------------------------------------------------------

   1 - (rowset=256) "TABLE_NAME"[VARCHAR2,128]

Note

PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------

-----
   - SQL plan baseline SQL_PLAN_7hy1htv240ayzc127edb7 used for this statement


已選擇 47 行。

 能夠看到此時的執行計劃就是剛剛加HINTS的SQL語句的執行計劃了。

相關文章
相關標籤/搜索