【DB筆試面試610】在Oracle中,SPM的使用有哪些步驟?

  • 2019 年 10 月 10 日
  • 筆記

題目部分

在Oracle中,SPM的使用有哪些步驟?

答案部分

取消自動捕獲,也可以不取消自動捕捉:

show parameter baselines  ALTER SYSTEM SET OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES=FALSE;  

執行:

[ZHLHRSPMDB2:oracle]:/oracle>ORACLE_SID=dlhr  [ZHLHRSPMDB2:oracle]:/oracle>sqlplus / as sysdba    SQL*Plus: Release 11.2.0.4.0 Production on Thu May 26 15:47:55 2016    Copyright (c) 1982, 2013, Oracle.  All rights reserved.      Connected to:  Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production  With the Partitioning, Real Application Clusters, OLAP, Data Mining  and Real Application Testing options    SYS@dlhr> conn lhr/lhr  Connected.  LHR@dlhr>  LHR@dlhr>  LHR@dlhr>  LHR@dlhr> select * from v$version;    BANNER  --------------------------------------------------------------------------------  Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production  PL/SQL Release 11.2.0.4.0 - Production  CORE    11.2.0.4.0      Production  TNS for IBM/AIX RISC System/6000: Version 11.2.0.4.0 - Production  NLSRTL Version 11.2.0.4.0 - Production    LHR@dlhr> show parameter baselines    NAME                                 TYPE        VALUE  ------------------------------------ ----------- ------------------------------  optimizer_capture_sql_plan_baselines boolean     TRUE  optimizer_use_sql_plan_baselines     boolean     TRUE    LHR@dlhr> ALTER SYSTEM SET OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES=FALSE;    System altered.  

–創建表並插入數據,腳本:

CREATE TABLE tb_spm_test_lhr (   id           NUMBER,    description  VARCHAR2(50)  );    DECLARE    TYPE t_tab IS TABLE OF tb_spm_test_lhr%ROWTYPE;    l_tab t_tab := t_TAB();  BEGIN    FOR i IN 1 .. 10000 LOOP      l_tab.extend;      l_tab(l_tab.last).id := i;     l_tab(l_tab.last).description := 'Description for ' || i;    END LOOP;      FORALL i IN l_tab.first .. l_tab.last      INSERT INTO tb_spm_test_lhr VALUES l_tab(i);      COMMIT;   END;   /      EXEC DBMS_STATS.gather_table_stats(USER, 'tb_spm_test_lhr', cascade=>TRUE);    set autot trace  SELECT description FROM   tb_spm_test_lhr WHERE  id = 100;  

開始執行:

LHR@dlhr> CREATE TABLE tb_spm_test_lhr (    2   id           NUMBER,    3    description  VARCHAR2(50)    4  );    Table created.    LHR@dlhr>  LHR@dlhr> DECLARE    2    TYPE t_tab IS TABLE OF tb_spm_test_lhr%ROWTYPE;    3    l_tab t_tab := t_TAB();    4  BEGIN    5    FOR i IN 1 .. 10000 LOOP    6      l_tab.extend;    7      l_tab(l_tab.last).id := i;    8     l_tab(l_tab.last).description := 'Description for ' || i;    9    END LOOP;   10   11    FORALL i IN l_tab.first .. l_tab.last   12      INSERT INTO tb_spm_test_lhr VALUES l_tab(i);   13   14    COMMIT;   15   END;   16   /    PL/SQL procedure successfully completed.      LHR@dlhr> set autot trace  LHR@dlhr> SELECT description FROM   tb_spm_test_lhr WHERE  id = 100;      Execution Plan  ----------------------------------------------------------  Plan hash value: 2196561629    -------------------------------------------------------------------------------------  | Id  | Operation         | Name            | Rows  | Bytes | Cost (%CPU)| Time     |  -------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT  |                 |     1 |    40 |    13   (0)| 00:00:01 |  |*  1 |  TABLE ACCESS FULL| TB_SPM_TEST_LHR |     1 |    40 |    13   (0)| 00:00:01 |  -------------------------------------------------------------------------------------    Predicate Information (identified by operation id):  ---------------------------------------------------       1 - filter("ID"=100)    Note  -----     - dynamic sampling used for this statement (level=2)      Statistics  ----------------------------------------------------------            4  recursive calls            0  db block gets           94  consistent gets            0  physical reads            0  redo size          546  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client            0  sorts (memory)            0  sorts (disk)            1  rows processed  

獲取剛才查詢的SQL_ID:

set autot off  col SQL_TEXT format a100  select distinct a.SQL_ID,a.SQL_TEXT from v$sql a  WHERE a.SQL_TEXT like '%SELECT description FROM   tb_spm_test_lhr WHERE  id = 100%'  and a.SQL_TEXT not like '%v$sql%'  AND    sql_text NOT LIKE '%EXPLAIN%';    LHR@dlhr> set autot off  LHR@dlhr> col SQL_TEXT format a100  LHR@dlhr> select distinct a.SQL_ID,a.SQL_TEXT from v$sql a    2  WHERE a.SQL_TEXT like '%SELECT description FROM   tb_spm_test_lhr WHERE  id = 100%'    3  and a.SQL_TEXT not like '%v$sql%'    4  AND    sql_text NOT LIKE '%EXPLAIN%';    SQL_ID        SQL_TEXT  ------------- ----------------------------------------------------------------------------------------------------  garkwg3yy2ram SELECT description FROM   tb_spm_test_lhr WHERE  id = 100    ----使用SQL_ID 從cursor cache中手工捕獲執行計劃:  SET SERVEROUTPUT ON  DECLARE   l_plans_loaded  PLS_INTEGER;  BEGIN   l_plans_loaded := DBMS_SPM.load_plans_from_cursor_cache(     sql_id => '&sql_id');   DBMS_OUTPUT.put_line('Plans Loaded: ' || l_plans_loaded);  END;  /  -- --使用DBA_SQL_PLAN_BASELINES視圖查看SPM 資訊:  col sql_handle for a35  col plan_name for a35  set lin 300  SELECT SQL_HANDLE,plan_name,origin,enabled,accepted,fixed  FROM   dba_sql_plan_baselines  WHERE  sql_text LIKE '%tb_spm_test_lhr%'  AND    sql_text NOT LIKE'%dba_sql_plan_baselines%';    --刷新Share Pool,使下次SQL 執行時必須進行硬解析:  ALTER SYSTEM FLUSH SHARED_POOL;    LHR@dlhr> SET SERVEROUTPUT ON  LHR@dlhr> DECLARE    2   l_plans_loaded  PLS_INTEGER;    3  BEGIN    4   l_plans_loaded := DBMS_SPM.load_plans_from_cursor_cache(    5     sql_id => '&sql_id');    6   DBMS_OUTPUT.put_line('Plans Loaded: ' || l_plans_loaded);    7  END;    8  /  Enter value for sql_id: garkwg3yy2ram  old   5:    sql_id => '&sql_id');  new   5:    sql_id => 'garkwg3yy2ram');  Plans Loaded: 1    PL/SQL procedure successfully completed.      LHR@dlhr> col sql_handle for a35  LHR@dlhr> col plan_name for a35  LHR@dlhr> set lin 300  LHR@dlhr> SELECT sql_handle, plan_name,enabled, accepted    2  FROM   dba_sql_plan_baselines    3  WHERE  sql_text LIKE '%tb_spm_test_lhr%'    4  AND    sql_text NOT LIKE'%dba_sql_plan_baselines%';    SQL_HANDLE                          PLAN_NAME                           ENA ACC  ----------------------------------- ----------------------------------- --- ---  SQL_4f19d3cf57be7303                SQL_PLAN_4y6fmtxbvwws3184920d2      YES YES    LHR@dlhr> ALTER SYSTEM FLUSH SHARED_POOL;    System altered.    LHR@dlhr> set autot trace  SELECT description FROM   tb_spm_test_lhr WHERE  id = 100;  LHR@dlhr>    Execution Plan  ----------------------------------------------------------  Plan hash value: 2196561629    -------------------------------------------------------------------------------------  | Id  | Operation         | Name            | Rows  | Bytes | Cost (%CPU)| Time     |  -------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT  |                 |     1 |    40 |    13   (0)| 00:00:01 |  |*  1 |  TABLE ACCESS FULL| TB_SPM_TEST_LHR |     1 |    40 |    13   (0)| 00:00:01 |  -------------------------------------------------------------------------------------    Predicate Information (identified by operation id):  ---------------------------------------------------       1 - filter("ID"=100)    Note  -----     - dynamic sampling used for this statement (level=2)     - SQL plan baseline "SQL_PLAN_4y6fmtxbvwws3184920d2" used for this statement      Statistics  ----------------------------------------------------------          555  recursive calls           16  db block gets          667  consistent gets            0  physical reads         3056  redo size          546  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client           32  sorts (memory)            0  sorts (disk)            1  rows processed      --創建索引,收集統計資訊,並查詢相同的SQL:  CREATE INDEX spm_test_tab_idx ON tb_spm_test_lhr(id);  EXEC DBMS_STATS.gather_table_stats(USER,'tb_spm_test_lhr', cascade=>TRUE);    set autot trace  SELECT description FROM   tb_spm_test_lhr WHERE  id = 100;      LHR@dlhr> CREATE INDEX spm_test_tab_idx ON tb_spm_test_lhr(id);  Index created.    LHR@dlhr> EXEC DBMS_STATS.gather_table_stats(USER,'tb_spm_test_lhr', cascade=>TRUE);      PL/SQL procedure successfully completed.    LHR@dlhr>  LHR@dlhr>  LHR@dlhr>  LHR@dlhr> set autot trace  LHR@dlhr> SELECT description FROM   tb_spm_test_lhr WHERE  id = 100;        Execution Plan  ----------------------------------------------------------  Plan hash value: 2196561629    -------------------------------------------------------------------------------------  | Id  | Operation         | Name            | Rows  | Bytes | Cost (%CPU)| Time     |  -------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT  |                 |     1 |    25 |    13   (0)| 00:00:01 |  |*  1 |  TABLE ACCESS FULL| TB_SPM_TEST_LHR |     1 |    25 |    13   (0)| 00:00:01 |  -------------------------------------------------------------------------------------    Predicate Information (identified by operation id):  ---------------------------------------------------       1 - filter("ID"=100)    Note  -----     - SQL plan baseline "SQL_PLAN_4y6fmtxbvwws3184920d2" used for this statement      Statistics  ----------------------------------------------------------          640  recursive calls           39  db block gets          493  consistent gets            2  physical reads        12268  redo size          546  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client           10  sorts (memory)            0  sorts (disk)            1  rows processed      --這裡我們創建了索引,但是這裡還是走的全表掃描,這裡使用索引明顯才是最優的方案。  --查看SPM 視圖:  set autot off  col sql_handle for a35  col plan_name for a35  set lin 300  SELECT SQL_HANDLE,plan_name,origin,enabled,accepted,fixed  FROM   dba_sql_plan_baselines  WHERE  sql_text LIKE '%tb_spm_test_lhr%'  AND    sql_text NOT LIKE'%dba_sql_plan_baselines%';    LHR@dlhr> set autot off  LHR@dlhr> col sql_handle for a35  LHR@dlhr> col plan_name for a35  LHR@dlhr> set lin 300  LHR@dlhr> SELECT sql_handle, plan_name,enabled, accepted    2  FROM   dba_sql_plan_baselines    3  WHERE  sql_text LIKE '%tb_spm_test_lhr%'    4  AND    sql_text NOT LIKE'%dba_sql_plan_baselines%';    SQL_HANDLE                          PLAN_NAME                           ENA ACC  ----------------------------------- ----------------------------------- --- ---  SQL_4f19d3cf57be7303                SQL_PLAN_4y6fmtxbvwws3184920d2      YES YES  SQL_4f19d3cf57be7303                SQL_PLAN_4y6fmtxbvwws38b725570      YES NO    --通過BASELINES查詢的結果,可以看到SQL產生了兩條執行計劃,但是最優的執行計劃並沒有被標記為ACCEPT,所以沒有使用。  --下邊我們演化執行計劃:演化就是將cost低的執行計劃標記為accept:  LHR@dlhr> SET LONG 10000  LHR@dlhr> SELECT DBMS_SPM.evolve_sql_plan_baseline(sql_handle => '&sql_handle') FROM dual;  Enter value for sql_handle: SQL_4f19d3cf57be7303  old   1: SELECT DBMS_SPM.evolve_sql_plan_baseline(sql_handle => '&sql_handle') FROM dual  new   1: SELECT DBMS_SPM.evolve_sql_plan_baseline(sql_handle => 'SQL_4f19d3cf57be7303') FROM dual    DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE(SQL_HANDLE=>'SQL_4F19D3CF57BE7303')  --------------------------------------------------------------------------------    -------------------------------------------------------------------------------                          Evolve SQL Plan Baseline Report  -------------------------------------------------------------------------------    Inputs:  -------    SQL_HANDLE = SQL_4f19d3cf57be7303    PLAN_NAME  =    TIME_LIMIT = DBMS_SPM.AUTO_LIMIT    VERIFY     = YES    COMMIT     = YES    Plan: SQL_PLAN_4y6fmtxbvwws38b725570  ------------------------------------    Plan was verified: Time used .018 seconds.    Plan passed performance criterion: 15 times better than baseline plan.    Plan was changed to an accepted plan.                                Baseline Plan      Test Plan       Stats Ratio                              -------------      ---------       -----------    Execution Status:              COMPLETE       COMPLETE    Rows Processed:                       1              1    Elapsed Time(ms):                  .308           .025             12.32    CPU Time(ms):                      .164           .015             10.93    Buffer Gets:                         45              3                15    Physical Read Requests:               0              0    Physical Write Requests:              0              0    Physical Read Bytes:                  0              0    Physical Write Bytes:                 0              0    Executions:                           1              1    -------------------------------------------------------------------------------                                   Report Summary  -------------------------------------------------------------------------------  Number of plans verified: 1  Number of plans accepted: 1      --再次查看DBA_SQL_PLAN_BASELINES視圖:  set autot off  col sql_handle for a35  col plan_name for a35  set lin 300  SELECT SQL_HANDLE,plan_name,origin,enabled,accepted,fixed  FROM   dba_sql_plan_baselines  WHERE  sql_text LIKE '%tb_spm_test_lhr%'  AND    sql_text NOT LIKE'%dba_sql_plan_baselines%';    LHR@dlhr> set autot off  LHR@dlhr> col sql_handle for a35  LHR@dlhr> col plan_name for a35  LHR@dlhr> set lin 300  LHR@dlhr> SELECT sql_handle, plan_name,enabled, accepted    2  FROM   dba_sql_plan_baselines    3  WHERE  sql_text LIKE '%tb_spm_test_lhr%'    4  AND    sql_text NOT LIKE'%dba_sql_plan_baselines%';    SQL_HANDLE                          PLAN_NAME                           ENA ACC  ----------------------------------- ----------------------------------- --- ---  SQL_4f19d3cf57be7303                SQL_PLAN_4y6fmtxbvwws3184920d2      YES YES  SQL_4f19d3cf57be7303                SQL_PLAN_4y6fmtxbvwws38b725570      YES YES    --再次執行SQL:  set autot trace  SELECT description FROM   tb_spm_test_lhr WHERE  id = 100;    LHR@dlhr> set autot trace  LHR@dlhr> SELECT description FROM   tb_spm_test_lhr WHERE  id = 100;      Execution Plan  ----------------------------------------------------------  Plan hash value: 2587945646    ------------------------------------------------------------------------------------------------  | Id  | Operation                   | Name             | Rows  | Bytes | Cost (%CPU)| Time     |  ------------------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT            |                  |     1 |    25 |     2   (0)| 00:00:01 |  |   1 |  TABLE ACCESS BY INDEX ROWID| TB_SPM_TEST_LHR  |     1 |    25 |     2   (0)| 00:00:01 |  |*  2 |   INDEX RANGE SCAN          | SPM_TEST_TAB_IDX |     1 |       |     1   (0)| 00:00:01 |  ------------------------------------------------------------------------------------------------    Predicate Information (identified by operation id):  ---------------------------------------------------       2 - access("ID"=100)    Note  -----     - SQL plan baseline "SQL_PLAN_4y6fmtxbvwws38b725570" used for this statement      Statistics  ----------------------------------------------------------           13  recursive calls           14  db block gets           18  consistent gets            0  physical reads         3048  redo size          553  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client            0  sorts (memory)            0  sorts (disk)            1  rows processed  

這次正確的使用了索引。因為只有標記為ENABLE和ACCEPT的plan才可以被使用。

下面示例將我們的第一個走全表掃描的執行計劃標記為fixed。標記為fixed的執行計劃會被優先使用。FIXED表示優化程式僅考慮標記為FIXED的計劃,而不考慮其它計劃。例如,如果有10個基準線計劃,其中的三個計劃被標記為FIXED,則優化程式將僅使用這三個計劃中的最佳計劃,而忽略其它所有計劃。如果某個SQL計劃基準線至少包含一個已啟用的已修復計劃,則該SQL計劃基準線就是FIXED的。如果在修復的SQL計劃基準線中添加了新計劃,則在手動將這些新計劃聲明為FIXED之前,無法使用這些新計劃。

set autot off  select * from table(dbms_xplan.display_sql_plan_baseline (sql_handle => '&sql_handle', format => 'basic'));    SET SERVEROUTPUT ON  DECLARE   l_plans_altered  PLS_INTEGER;  BEGIN   l_plans_altered := DBMS_SPM.alter_sql_plan_baseline(     sql_handle      => '&sql_handle',     plan_name       => '&plan_name',     attribute_name  => 'fixed',     attribute_value => 'YES');     DBMS_OUTPUT.put_line('Plans Altered: ' || l_plans_altered);  END;  /    LHR@dlhr> SET SERVEROUTPUT ON  LHR@dlhr> DECLARE    2   l_plans_altered  PLS_INTEGER;    3  BEGIN    4   l_plans_altered := DBMS_SPM.alter_sql_plan_baseline(    5     sql_handle      => '&sql_handle',    6     plan_name       => '&plan_name',    7     attribute_name  => 'fixed',    8     attribute_value => 'YES');    9   10   DBMS_OUTPUT.put_line('Plans Altered: ' || l_plans_altered);   11  END;   12  /  Enter value for sql_handle: SQL_4f19d3cf57be7303  old   5:    sql_handle      => '&sql_handle',  new   5:    sql_handle      => 'SQL_4f19d3cf57be7303',  Enter value for plan_name: SQL_PLAN_4y6fmtxbvwws3184920d2  old   6:    plan_name       => '&plan_name',  new   6:    plan_name       => 'SQL_PLAN_4y6fmtxbvwws3184920d2',  Plans Altered: 1    PL/SQL procedure successfully completed.    --驗證:  set autot off  col sql_handle for a35  col plan_name for a35  set lin 300  SELECT SQL_HANDLE,plan_name,origin,enabled,accepted,fixed  FROM   dba_sql_plan_baselines  WHERE  sql_text LIKE '%tb_spm_test_lhr%'  AND    sql_text NOT LIKE'%dba_sql_plan_baselines%';    LHR@dlhr> set autot off  LHR@dlhr> select * from table(dbms_xplan.display_sql_plan_baseline (sql_handle => '&sql_handle', format => 'basic'));  Enter value for sql_handle: SQL_4f19d3cf57be7303  old   1: select * from table(dbms_xplan.display_sql_plan_baseline (sql_handle => '&sql_handle', format => 'basic'))  new   1: select * from table(dbms_xplan.display_sql_plan_baseline (sql_handle => 'SQL_4f19d3cf57be7303', format => 'basic'))    PLAN_TABLE_OUTPUT  --------------------------------------------------------------------------------------    --------------------------------------------------------------------------------  SQL handle: SQL_4f19d3cf57be7303  SQL text: SELECT description FROM   tb_spm_test_lhr WHERE  id = 100  --------------------------------------------------------------------------------    --------------------------------------------------------------------------------  Plan name: SQL_PLAN_4y6fmtxbvwws3184920d2         Plan id: 407445714  Enabled: YES     Fixed: YES     Accepted: YES     Origin: MANUAL-LOAD  --------------------------------------------------------------------------------    Plan hash value: 2196561629    ---------------------------------------------  | Id  | Operation         | Name            |  ---------------------------------------------  |   0 | SELECT STATEMENT  |                 |  |   1 |  TABLE ACCESS FULL| TB_SPM_TEST_LHR |  ---------------------------------------------    --------------------------------------------------------------------------------  Plan name: SQL_PLAN_4y6fmtxbvwws38b725570         Plan id: 2339526000  Enabled: YES     Fixed: NO      Accepted: YES     Origin: AUTO-CAPTURE  --------------------------------------------------------------------------------    Plan hash value: 2587945646    --------------------------------------------------------  | Id  | Operation                   | Name             |  --------------------------------------------------------  |   0 | SELECT STATEMENT            |                  |  |   1 |  TABLE ACCESS BY INDEX ROWID| TB_SPM_TEST_LHR  |  |   2 |   INDEX RANGE SCAN          | SPM_TEST_TAB_IDX |  --------------------------------------------------------    34 rows selected.    LHR@dlhr> set autot off  LHR@dlhr> col sql_handle for a35  LHR@dlhr> col plan_name for a35  LHR@dlhr> set lin 300  LHR@dlhr> SELECT SQL_HANDLE,plan_name,origin,enabled,accepted,fixed    2  FROM   dba_sql_plan_baselines    3  WHERE  sql_text LIKE '%tb_spm_test_lhr%'    4  AND    sql_text NOT LIKE'%dba_sql_plan_baselines%';    SQL_HANDLE                          PLAN_NAME                           ORIGIN         ENA ACC FIX  ----------------------------------- ----------------------------------- -------------- --- --- ---  SQL_4f19d3cf57be7303                SQL_PLAN_4y6fmtxbvwws3184920d2      MANUAL-LOAD    YES YES YES  SQL_4f19d3cf57be7303                SQL_PLAN_4y6fmtxbvwws38b725570      AUTO-CAPTURE   YES YES NO        --再次查看我們之前的SQL:  set autot trace  SELECT description FROM   tb_spm_test_lhr WHERE  id = 100;    LHR@dlhr> set autot trace  LHR@dlhr> SELECT description FROM   tb_spm_test_lhr WHERE  id = 100;      Execution Plan  ----------------------------------------------------------  Plan hash value: 2196561629    -------------------------------------------------------------------------------------  | Id  | Operation         | Name            | Rows  | Bytes | Cost (%CPU)| Time     |  -------------------------------------------------------------------------------------  |   0 | SELECT STATEMENT  |                 |     1 |    25 |    13   (0)| 00:00:01 |  |*  1 |  TABLE ACCESS FULL| TB_SPM_TEST_LHR |     1 |    25 |    13   (0)| 00:00:01 |  -------------------------------------------------------------------------------------    Predicate Information (identified by operation id):  ---------------------------------------------------       1 - filter("ID"=100)    Note  -----     - SQL plan baseline "SQL_PLAN_4y6fmtxbvwws3184920d2" used for this statement      Statistics  ----------------------------------------------------------            6  recursive calls            8  db block gets           46  consistent gets            0  physical reads            0  redo size          546  bytes sent via SQL*Net to client          519  bytes received via SQL*Net from client            2  SQL*Net roundtrips to/from client            0  sorts (memory)            0  sorts (disk)            1  rows processed  

這裡已經走了全表掃描,根據前邊的示例,我們知道這裡走索引會更優,但因為我們將走全表掃描的執行計劃設置為fixed,所以優先使用這個執行計劃。

& 說明:

有關固定執行計劃的具體過程及更多的知識可以參考我的BLOG:http://blog.itpub.net/26736162/viewspace-2107604/

本文選自《Oracle程式設計師面試筆試寶典》,作者:李華榮。