设为首页 收藏本站
查看: 1005|回复: 0

[经验分享] Oracle固定SQL的执行计划(二)---SPM

[复制链接]

尚未签到

发表于 2018-10-20 12:56:06 | 显示全部楼层 |阅读模式
  之前写了一篇博客介绍的是用SQL Profile来调整、稳定目标SQL的执行计划,即使无法修改目标SQL的SQL文本。但SQL Profile实际上只是一种亡羊补牢、被动的技术手段,应用在那些执行计划已经发生了不好的变更的SQL上,即当我们发现这些SQL的执行计划已经出了问题时通过创建SQL Profile来纠正、稳定这些SQL的执行计划。即便通过创建SQL Profile解决了目标SQL执行计划变更的问题,依然不能保证系统后续执行的SQL的执行计划就不再发生不好的变更。这种不确定性会给Oracle数据库大版本升级(比如从Oracle 10g升级到Oracle 11g)带来一系列的麻烦,因为不清楚升级之后原先系统中哪些SQL的执行计划会发生不好的变更。
  为了解决上述问题,Oracle在11g中推出了SPM(SQL Plan Management)。SPM是一种主动的稳定执行计划的手段,能够保证只有被验证过的执行计划才会被启用,当由于种种原因(如统计信息的变更)而导致目标SQL产生了新的执行计划后,这个新的执行计划并不会被马上启用,直到它已经被我们验证过其执行效率会比原先执行计划高才会被启用。
  随着Oracle数据库版本的不段推进,其CBO的算法、功能也在一直不断进化和增加,所以同样的SQL有可能在新版本的Oralce数据库中执行效率更高,如果我们使用了SQL Profile(特别是使用了Manual类型的SQL Profile)来稳定目标SQL的执行计划,那就意味着可能失去了继续优化上述SQL的执行效率的机会。而SPM的推出可以说彻底解决了执行计划稳定性的问题,它既能主动地稳定执行计划,又保留了继续使用新的执行效率可能更高的执行计划的机会。
  当启用了SPM后,每一个SQL都会存在对应的SQL Plan Baseline,这个SQL Plan Baseline里存储的就是该SQL的执行计划,如果一个SQL有多个执行计划,那么该SQL就可能会有多个SQL Plan Baseline,可以从DBA_SQL_PLAN_BASELINES中查看目标SQL所有的SQL Plan Baseline。
  DBA_SQL_PLAN_BASELINES中的列ENABLED和ACCEPTED用来描述一个SQL Plan Baseline所对应的执行计划是否能被Oracle启用,只有ENABLED和ACCEPTED的值均为“YES”的SQL Plan Baseline所对应的执行计划才会被Oracle启用,如果一具SQL有超过1个以上的SQL Plan Baseline的ENABLED和ACCEPTED的值均为YES,则Oracle会从中选择成本值最小的一个所对应的执行坟墓来作为该SQL的执行计划。
  在Oracle 11g及其以上的版本中,有如下两种方法可以产生目标SQL的SQL Plan Baseline。

  •   自动捕获
  •   手工生成/批量导入(批量导入尤其适用于Oracle数据库大版本的升级,它可以确保升级后原有系统所胡SQL的执行计划不会发生变化)
  下面分别介绍如何自动捕获和手工的方式来产生SQL Plan Baseline。
  1 自动捕获SQL Plan Baseline
  参数OPTIMIZER_CAPTURE_SQL_PLAN_BASELINES用于控制是否开启自动捕获SQL Plan Baseline,其默认值为FALSE,表示在默认情况下,Oracle并不会自动捕获SQL Plan Baseline。这个参数可以在session或系统级别动态修改。当修改为TRUE后,则Oracle会对上述参数影响范围内所有重复执行的SQL自动捕获其SQL Plan Baseline,并且针对目标SQL第一次捕获的SQL Plan Baseline的ENABLED和ACCEPTED的值均为“YES”。随后如果该SQL的执行计划发生了变更,则再次捕获到的SQL Plan Baseline的ENABLED的值依然为YES,但ACCEPTED的值变为了NO,这表示后续变更的执行计划虽然被捕获了,但Oracle不会将其作为该SQL的执行计划来执行,即此时Oracle会永远沿用该SQL第一次被捕获的SQL Plan Baseline所对应的执行计划(除非后续做了手工调整)。
  参数OPTIMIZER_USE_SQL_PLAN_BASELINES用于控制是否启用SQL Plan Baseline,其默认值为TRUE,表示在默认情况下,Oracle在生成执行计划时就会启用SPM,使用已有的SQL Plan Baseline,这个参数也可以在session或系统级别动态修改。
  下面看一下实例:
  查看上述两个参数的默认值
zx@MYDB>show parameter sql_plan  

  
NAME                                 TYPE                              VALUE
  
------------------------------------ --------------------------------- ------------------------------
  
optimizer_capture_sql_plan_baselines boolean                           FALSE
  
optimizer_use_sql_plan_baselines     boolean                           TRUE
  在当前session中禁掉SPM并同时开启自动捕获SQL Plan Baseline:
zx@MYDB>alter session set optimizer_use_sql_plan_baselines=FALSE;  

  
Session altered.
  

  
zx@MYDB>alter session set optimizer_capture_sql_plan_baselines=TRUE;
  

  
Session altered.
  创建测试表T2
zx@MYDB>create table t2 as select * from dba_objects;  

  
Table created.
  

  
zx@MYDB>create index idx_t2 on t2(object_id);
  

  
Index created.
  

  
zx@MYDB>exec dbms_stats.gather_table_stats(ownname=>USER,tabname=>'T2',estimate_percent=>100,cascade=>true);
  

  
PL/SQL procedure successfully completed.
  

  
zx@MYDB>select object_id,object_name from t2 where object_id between 103 and 108;
  

  
OBJECT_ID OBJECT_NAME
  
---------- ------------------------------
  
       103 MIGRATE$
  
       104 DEPENDENCY$
  
       105 ACCESS$
  
       106 I_DEPENDENCY1
  
       107 I_DEPENDENCY2
  
       108 I_ACCESS1
  

  
6 rows selected.
DSC0000.png

  从执行计划上看,走的是索引IDX_T2上的索引范围扫描,因为SQL只执行了一次,所以Oracle不会自动捕获SQL Plan Baseline,DBA_SQL_PLAN_BASELINES中没有记录
zx@MYDB>col sql_handle for a30  
zx@MYDB>col plan_name for a30
  
zx@MYDB>col origin for a20
  
zx@MYDB>col sql_text for a70
  
zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines;
  

  
no rows selected
  再次执行上述SQL,因为重复执行该SQL,Oracle自动捕获了这个SQL的SQL Plan Baseline
zx@MYDB>select object_id,object_name from t2 where object_id between 103 and 108;  

  
OBJECT_ID OBJECT_NAME
  
---------- ------------------------------
  
       103 MIGRATE$
  
       104 DEPENDENCY$
  
       105 ACCESS$
  
       106 I_DEPENDENCY1
  
       107 I_DEPENDENCY2
  
       108 I_ACCESS1
  

  
6 rows selected.
  

  
zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines;
  

  
SQL_HANDLE                     PLAN_NAME                      ORIGIN                ENABLED   ACCEPTED  SQL_TEXT
  
------------------------------ ------------------------------ -------------------- --------- --------- ------------------------------------------------------------
  
SYS_SQL_ac526b1e4be74880       SQL_PLAN_asnmb3t5yfk4024c6dbb6 AUTO-CAPTURE          YES       YES       select object_id,object_name from t2 where object_id between 103 and 108
  现在将索引IDX_T2的聚簇因子修改为2400万,目的是为了能让SQL的执行计划变为对表T2的全表扫描(为何修改聚簇因子,参考http://hbxztc.blog.51cto.com/1587495/1901258)。修改完后再执行上述SQL,并查看执行计划:
zx@MYDB>exec dbms_stats.set_index_stats(ownname=>USER,indname=>'IDX_T2',clstfct=>24000000,no_invalidate=>false);  

  
PL/SQL procedure successfully completed.
  

  
zx@MYDB>select index_name,clustering_factor from dba_indexes where index_name='IDX_T2';
  

  
INDEX_NAME                                                                                 CLUSTERING_FACTOR
  
------------------------------------------------------------------------------------------ -----------------
  
IDX_T2                                                                                              24000000
  

  
zx@MYDB>select object_id,object_name from t2 where object_id between 103 and 108;
  

  
OBJECT_ID OBJECT_NAME
  
---------- ------------------------------
  
       103 MIGRATE$
  
       104 DEPENDENCY$
  
       105 ACCESS$
  
       106 I_DEPENDENCY1
  
       107 I_DEPENDENCY2
  
       108 I_ACCESS1
  

  
6 rows selected.
DSC0001.png

  从执行计划中可以看出该SQL的执行计划已经变为全表扫描。因为目标SQL已经重复执行且同时又产生了一个新的执行计划,所以现在Oracle就会自动捕获并创建这个新的执行计划所对应的SQL Plan Baseline了。从如下查询可以看出Oracle对新的执行计划产生了一个新的SQL Plan Baseline,其ENABLED的值依然为YES,但ACCEPTED的值变为了NO:
DSC0002.png 现在我们对当前Session关闭自动捕获SQL Plan Baseline并同时开启SPM,现在索引IDX_T2的聚簇因子依然为2400万,再次执行目标SQL,并查看执行计划:

zx@MYDB>alter session set optimizer_use_sql_plan_baselines=TRUE;  

  
Session altered.
  

  
zx@MYDB>alter session set optimizer_capture_sql_plan_baselines=FALSE;
  

  
Session altered.
  

  

  
zx@MYDB>select index_name,clustering_factor from dba_indexes where index_name='IDX_T2';
  

  
INDEX_NAME                                                                                 CLUSTERING_FACTOR
  
------------------------------------------------------------------------------------------ -----------------
  
IDX_T2                                                                                              24000000
  

  
zx@MYDB>select object_id,object_name from t2 where object_id between 103 and 108;
  

  
OBJECT_ID OBJECT_NAME
  
---------- ------------------------------
  
       103 MIGRATE$
  
       104 DEPENDENCY$
  
       105 ACCESS$
  
       106 I_DEPENDENCY1
  
       107 I_DEPENDENCY2
  
       108 I_ACCESS1
  

  
6 rows selected.
DSC0003.png

DSC0004.png

  从上面的显示内容可以看出,现在目标SQL的执行又从全表扫描恢复为了索引范围扫描,并且执行计划中的Note部分有“SQL plan baseline SQL_PLAN_asnmb3t5yfk4024c6dbb6 used for this statement”内容,说明SPM开启的情况下,即便目标SQL产生了新的执行计划,Oracle依然只会应用该SQL的ENABLED和ACCEPTED的值均为YES的SQL Plan Baselline。
  如果想启用目标SQL新的执行计划(即全表扫描),应该如何做呢?
  针对不同的Oracle版本,会有不同的处理方法。比如这里想启用目标SQL的新的执行计划,如果是11gR1的环境,则只需要将目标SQL所采用的名为SQL_PLAN_asnmb3t5yfk4024c6dbb6的SQL Plan Baseline(即索引范围扫描)的ACCEPTED的值设为NO就可以了。但对于11gR2环境,上述方法会报错,因为在11gR2中,所有已经被ACCEPTED的SQL Plan Baseline的ACCEPTED的值将不再能够被设为NO:
zx@MYDB>var temp varchar2(1000);  
zx@MYDB>exec :temp := dbms_spm.alter_sql_plan_baseline(sql_handle=>'SYS_SQL_ac526b1e4be74880',plan_name=>'SQL_PLAN_asnmb3t5yfk4024c6dbb6',attribute_name=>'accepted',attribute_value=>'NO');
  
BEGIN :temp := dbms_spm.alter_sql_plan_baseline(sql_handle=>'SYS_SQL_ac526b1e4be74880',plan_name=>'SQL_PLAN_asnmb3t5yfk4024c6dbb6',attribute_name=>'accepted',attribute_value=>'NO'); END;
  

  
*
  
ERROR at line 1:
  
ORA-38136: invalid attribute name ACCEPTED specified
  
ORA-06512: at "SYS.DBMS_SPM", line 2469
  
ORA-06512: at line 1
  在11gR2中,我们可以联合使用DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE和DBMS_SPM.ALTER_SQL_PLAN_BASELINE达到启用目标SQL新的执行计划的目的。
  先用DBMS_SPM.EVOLVE_SQL_PLAN_BASELINE将新的执行计划(全表扫描)所对应的SQL Plan Baseline的ACCEPTED值设为“YES”:
zx@MYDB>exec :temp := dbms_spm.evolve_sql_plan_baseline(sql_handle=>'SYS_SQL_ac526b1e4be74880',plan_name=>'SQL_PLAN_asnmb3t5yfk40b860bcf2',verify=>'NO',commit=>'YES');  

  
PL/SQL procedure successfully completed.
DSC0005.png

  从上面显示的内容看到如下信息:“Plan: SQL_PLAN_asnmb3t5yfk40b860bcf2----Plan was changed to an accepted plan.”,这表明已经将新的执行计划(全表扫描)所对应的SQL Plan Baseline的ACCEPTED值设为YES
  从下面的查询结果也可以证明:
zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select object_id%';  

  
SQL_HANDLE       PLAN_NAME      ORIGIN   ENABLED   ACCEPTED  SQL_TEXT
  
------------------------------ ------------------------------ -------------------- --------- --------- ----------------------------------------------------------------------
  
SYS_SQL_ac526b1e4be74880       SQL_PLAN_asnmb3t5yfk4024c6dbb6 AUTO-CAPTURE   YES     YES       select object_id,object_name from t2 where object_id between 103 and 108
  

  

  
SYS_SQL_ac526b1e4be74880       SQL_PLAN_asnmb3t5yfk40b860bcf2 AUTO-CAPTURE   YES     YES       select object_id,object_name from t2 where object_id between 103 and 108
  然后再使用DBMS_SPM.ALTER_SQL_PLAN_BASELINE将原先的执行计划(索引范围扫描)对应的SQL Plan Baseline的ENABLED的值设为NO:
zx@MYDB>exec :temp := dbms_spm.alter_sql_plan_baseline(sql_handle=>'SYS_SQL_ac526b1e4be74880',plan_name=>'SQL_PLAN_asnmb3t5yfk4024c6dbb6',attribute_name=>'enabled',attribute_value=>'NO');  

  
PL/SQL procedure successfully completed.
  

  
zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select object_id%';
  

  
SQL_HANDLE       PLAN_NAME      ORIGIN   ENABLED   ACCEPTED  SQL_TEXT
  
------------------------------ ------------------------------ -------------------- --------- --------- ----------------------------------------------------------------------
  
SYS_SQL_ac526b1e4be74880       SQL_PLAN_asnmb3t5yfk4024c6dbb6 AUTO-CAPTURE   NO     YES       select object_id,object_name from t2 where object_id between 103 and 108
  

  

  
SYS_SQL_ac526b1e4be74880       SQL_PLAN_asnmb3t5yfk40b860bcf2 AUTO-CAPTURE   YES     YES       select object_id,object_name from t2 where object_id between 103 and 108
  再次执行目标SQL
zx@MYDB>select object_id,object_name from t2 where object_id between 103 and 108;  

  
OBJECT_ID OBJECT_NAME
  
---------- ------------------------------
  
       103 MIGRATE$
  
       104 DEPENDENCY$
  
       105 ACCESS$
  
       106 I_DEPENDENCY1
  
       107 I_DEPENDENCY2
  
       108 I_ACCESS1
  

  
6 rows selected.
DSC0006.png

DSC0007.png

  从上述显示可以看出,现在SQL的执行计划已经变为了全表扫描,我们要启用新的执行计划(全表扫描)的目的已经实现,Note部分也有了提示。
  从上述测试结果可以看出,实际上我们可以轻易地在目标SQL的多个执行计划中切换,所以SPM确实是既能够主动地稳定执行计划,又保留了继续使用新的执行计划的机会,并且我们很容易就能启用新的执行计划。
  下面介绍手工生成SQL Plan Baseline:
  手工生成目标SQL的SQL Plan Baseline其实非常简单,其核心就是调用DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE。这里只讨论针对单个SQL的SQL Plan Baseline的手工生成。
  之前介绍过用Manual类型的SQL Profile可以在不改变目标SQL的SQL文本的情况下调整其执行计划。实际上,用手工生成SQL Plan Baseline的方式也完全可以实现同样的目的,甚至会比使用Manual类型的SQL Profile更加简洁。
  手工生成目标SQL的SQL Plan Baseline的具体步骤为:
  1)针对目标SQL使用DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE手工生成其初始执行计划所对应的SQL Plan Baseline。此时,使用DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE传入的参数如下所示:
  dbms_spm.load_plans_from_cursor_cache(sql_id=>'原目标SQL的SQL_ID',plan_hash_value=>原目标SQL的PLAN HASH VALUE)
  2)改写原目标SQL的SQL文本,在其中加入合适的Hint,直到加入Hint后的所改写的SQL能走出我们想要的执行计划,然后对改写后的SQL使用DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE手工生成新的执行计划所对应的SQL Plan Baseline。此时传入的参数如下所示:
  dbms_spm.load_plans_from_cursor_cache(sql_id=>'加入合适Hint后改写SQL的SQL_ID',plan_hash_value=>加入合适Hint后改写SQL的PLAN HASH VALUE,sql_handle=>'原目标SQL在步骤(1)中所产生的SQL Plan Baseline的sql_handle')
  3)使用DBMS_SPM.LOAD_PLANS_FROM_CURSOR_CACHE删除步骤(1)中手工生成的原目标SQL的初始执行计划所对应的SQL Plan Baseline。此时传入的参数如下所示:
  dbms_spm.drop_sql_plan_baseline(sql_handle=>'原目标SQL在步骤(1)中所产生的SQL Plan Baseline的sql_handle',plan_name=>'原目标SQL在步骤(1)中所产生的SQL Plan Baseline的plan_name')
  下面使用一个实例演示:
zx@MYDB>select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_id=4;  

  
OBJECT_NAMEOBJECT_ID
  
------------------------------ ----------
  
TAB$4
  

  
zx@MYDB>select * from table(dbms_xplan.display_cursor(null,null,'advanced'));
  

  
PLAN_TABLE_OUTPUT
  
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  
SQL_ID0n5z3wmf8qpgn, child number 0
  
-------------------------------------
  
select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where
  
object_id=4
  

  
Plan hash value: 1513984157
  

  
--------------------------------------------------------------------------
  
| Id  | Operation  | Name | Rows  | Bytes | Cost (%CPU)| Time |
  
--------------------------------------------------------------------------
  
|   0 | SELECT STATEMENT  | | | |   287 (100)|  |
  
|*  1 |  TABLE ACCESS FULL| T2 |     1 |    30 |   287   (1)| 00:00:04 |
  
--------------------------------------------------------------------------
  

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

  
   1 - SEL$1 / T2@SEL$1
  

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

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

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

  
   1 - filter("OBJECT_ID"=4)
  

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

  
   1 - "OBJECT_NAME"[VARCHAR2,128], "OBJECT_ID"[NUMBER,22]
  

  

  
43 rows selected.
  

  
zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+ no_index(t2 idx_t2)%';
  

  
no rows selected
  

  
zx@MYDB>var temp number
  
zx@MYDB>exec :temp :=dbms_spm.load_plans_from_cursor_cache(sql_id=>'0n5z3wmf8qpgn',plan_hash_value=>1513984157);
  

  
PL/SQL procedure successfully completed.
  

  
zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+ no_index(t2 idx_t2)%';
  

  
SQL_HANDLE       PLAN_NAME      ORIGIN   ENABLED   ACCEPTED  SQL_TEXT
  
------------------------------ ------------------------------ -------------------- --------- --------- ----------------------------------------------------------------------
  
SYS_SQL_75b06ae056223f5f       SQL_PLAN_7bc3aw1b24guzb860bcf2 MANUAL-LOAD   YES     YES       select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_i
  d=4
  从上述显示目标SQL初始执行计划为全表扫描,sql_id和plan hash value可以从执行计划中找到,由于没有启用自动捕获SQL Plan Baseline,一开始没有查到目标SQL对应的SQL Plan Baseline,手工生成后,可以查到全表扫描对应的SQL Plan Baseline。
  改写原目标SQL,加入Hint后重新执行:
zx@MYDB>select /*+ index(t2 idx_t2) */ object_name,object_id from t2 where object_id=4;  

  
OBJECT_NAMEOBJECT_ID
  
------------------------------ ----------
  
TAB$4
  

  
zx@MYDB>select * from table(dbms_xplan.display_cursor(null,null,'advanced'));
  

  
PLAN_TABLE_OUTPUT
  
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  
SQL_ID60txg87j30pvw, child number 0
  
-------------------------------------
  
select /*+ index(t2 idx_t2) */ object_name,object_id from t2 where
  
object_id=4
  

  
Plan hash value: 2008370210
  

  
--------------------------------------------------------------------------------------
  
| Id  | Operation    | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
  
--------------------------------------------------------------------------------------
  
|   0 | SELECT STATEMENT    |     |     |     | 335 (100)|     |
  
|   1 |  TABLE ACCESS BY INDEX ROWID| T2     |   1 |  30 | 335   (0)| 00:00:05 |
  
|*  2 |   INDEX RANGE SCAN    | IDX_T2 |   1 |     |   1   (0)| 00:00:01 |
  
--------------------------------------------------------------------------------------
  

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

  
   1 - SEL$1 / T2@SEL$1
  
   2 - SEL$1 / T2@SEL$1
  

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

  
  /*+
  
      BEGIN_OUTLINE_DATA
  
      IGNORE_OPTIM_EMBEDDED_HINTS
  
      OPTIMIZER_FEATURES_ENABLE('11.2.0.1')
  
      DB_VERSION('11.2.0.1')
  
      ALL_ROWS
  
      OUTLINE_LEAF(@"SEL$1")
  
      INDEX_RS_ASC(@"SEL$1" "T2"@"SEL$1" ("T2"."OBJECT_ID"))
  
      END_OUTLINE_DATA
  
  */
  

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

  
   2 - access("OBJECT_ID"=4)
  

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

  
   1 - "OBJECT_NAME"[VARCHAR2,128], "OBJECT_ID"[NUMBER,22]
  
   2 - "T2".ROWID[ROWID,10], "OBJECT_ID"[NUMBER,22]
  

  

  
46 rows selected.
  

  
zx@MYDB>exec :temp :=dbms_spm.load_plans_from_cursor_cache(sql_id=>'60txg87j30pvw',plan_hash_value=>2008370210,sql_handle=>'SYS_SQL_75b06ae056223f5f');
  

  
PL/SQL procedure successfully completed.
  

  
zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+ no_index(t2 idx_t2)%';
  

  
SQL_HANDLE       PLAN_NAME      ORIGIN   ENABLED   ACCEPTED  SQL_TEXT
  
------------------------------ ------------------------------ -------------------- --------- --------- ----------------------------------------------------------------------
  
SYS_SQL_75b06ae056223f5f       SQL_PLAN_7bc3aw1b24guz24c6dbb6 MANUAL-LOAD   YES     YES       select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_i
  d=4
  

  
SYS_SQL_75b06ae056223f5f       SQL_PLAN_7bc3aw1b24guzb860bcf2 MANUAL-LOAD   YES     YES       select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_i
  d=4
  从上述输出可以看出把改写过的SQL的新的执行计划所对应的SQL Plan Baseline已经成功生成,而且所有手工生成的SQL Plan Baseline的ENABLED和ACCEPTED的值均为YES,这是和自动捕获的SQL Plan Baseline不一样的地方。
  Drop掉原执行计划(全表扫描)所对应的SQL Plan Baseline:
zx@MYDB>exec :temp := dbms_spm.drop_sql_plan_baseline(sql_handle=>'SYS_SQL_75b06ae056223f5f',plan_name=>'SQL_PLAN_7bc3aw1b24guzb860bcf2');  

  
PL/SQL procedure successfully completed.
  

  
zx@MYDB>select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+ no_index(t2 idx_t2)%';
  

  
SQL_HANDLE       PLAN_NAME      ORIGIN   ENABLED   ACCEPTED  SQL_TEXT
  
------------------------------ ------------------------------ -------------------- --------- --------- ----------------------------------------------------------------------
  
SYS_SQL_75b06ae056223f5f       SQL_PLAN_7bc3aw1b24guz24c6dbb6 MANUAL-LOAD   YES     YES       select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_i
  d=4
  再次执行原目标SQL,并查看执行计划
zx@MYDB>select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where object_id=4;  

  
OBJECT_NAMEOBJECT_ID
  
------------------------------ ----------
  
TAB$4
  

  
zx@MYDB>select * from table(dbms_xplan.display_cursor(null,null,'advanced'));
  

  
PLAN_TABLE_OUTPUT
  
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  
SQL_ID0n5z3wmf8qpgn, child number 2
  
-------------------------------------
  
select /*+ no_index(t2 idx_t2) */ object_name,object_id from t2 where
  
object_id=4
  

  
Plan hash value: 2008370210
  

  
--------------------------------------------------------------------------------------
  
| Id  | Operation    | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
  
--------------------------------------------------------------------------------------
  
|   0 | SELECT STATEMENT    |     |     |     | 335 (100)|     |
  
|   1 |  TABLE ACCESS BY INDEX ROWID| T2     |   1 |  30 | 335   (0)| 00:00:05 |
  
|*  2 |   INDEX RANGE SCAN    | IDX_T2 |   1 |     |   1   (0)| 00:00:01 |
  
--------------------------------------------------------------------------------------
  

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

  
   1 - SEL$1 / T2@SEL$1
  
   2 - SEL$1 / T2@SEL$1
  

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

  
  /*+
  
      BEGIN_OUTLINE_DATA
  
      IGNORE_OPTIM_EMBEDDED_HINTS
  
      OPTIMIZER_FEATURES_ENABLE('11.2.0.1')
  
      DB_VERSION('11.2.0.1')
  
      ALL_ROWS
  
      OUTLINE_LEAF(@"SEL$1")
  
      INDEX_RS_ASC(@"SEL$1" "T2"@"SEL$1" ("T2"."OBJECT_ID"))
  
      END_OUTLINE_DATA
  
  */
  

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

  
   2 - access("OBJECT_ID"=4)
  

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

  
   1 - "OBJECT_NAME"[VARCHAR2,128], "OBJECT_ID"[NUMBER,22]
  
   2 - "T2".ROWID[ROWID,10], "OBJECT_ID"[NUMBER,22]
  

  
Note
  
-----
  
   - SQL plan baseline SQL_PLAN_7bc3aw1b24guz24c6dbb6 used for this statement
  

  

  
50 rows selected.
  从上述输出可以看出,原目标SQL已经走了新的执行计划(索引范围扫描),而且Note部分也有提示“SQL plan baseline SQL_PLAN_7bc3aw1b24guz24c6dbb6 used for this statement”说明走了SPM。



运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-624091-1-1.html 上篇帖子: sql语句优化的十二条建议 下篇帖子: ubuntu server 相关配置
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表