2. 执行计划管理的测试
Oracle 11g提供了一个视图:dba_sql_plan_baselines,可以在该视图里查询某条SQL语句相关的plan
history以及plan baseline。我们来看下面的例子。
首先创建一个测试表。
SQL> create table t1(skew number,padding varchar2(100)); SQL> insert into t1 select rownum,object_name from dba_objects; SQL> commit; SQL> set autotrace traceonly exp stat; SQL> select * from t1 where skew=200; SQL> select * from t1 where skew=200;
尽管执行两次,但是这时去查询dba_sql_plan_baselines,试图找到SQL文本为select * from t1 where skew=200的记录时,会发现没有记录,因为optimizer_capture_sql_plan_baselines缺省为false。我们将该参数设置为true以后继续测试。
SQL> alter session set optimizer_capture_sql_plan_baselines=true; SQL> select * from t1 where skew=200; --全表扫描 SQL> select * from t1 where skew=200; --全表扫描 SQL> select signature,sql_handle,plan_name,origin,enabled,accepted, autopurge from dba_sql_plan_baselines where sql_text like 'select * from t1 where skew=200'; SIGNATURE SQL_HANDLE PLAN_NAME ORIGIN ENA ACC AUT ---------- ------------------------ ----------------------------- ----------- --- --- --- 1.2376E+19 SYS_SQL_abc0a2c042fa089c SYS_SQL_PLAN_42fa089c844cb98a AUTO-CAPTURE YES YES YES
我们可以看到,文本为“select * from t1 where skew=200”的SQL语句在plan history里产生了一个执行计划。其中,sql_handle表示SQL语句的句柄;plan_name则表示该SQL的执行计划的名字;origin表示该执行计划是如何进入plan history的,该列值为AUTO-CAPTURE则说明是由优化器自动加入的,如果为MANUAL则说明是由DBA手工加入的;enabled表示是否被启用了,YES表示启用,NO表示禁用。如果某个执行计划为禁用,则优化器根本就不会考虑使用该执行计划;accepted表示是否接受,也就是是否进入了plan baseline。我们看到这里的accepted为YES,说明该SQL的执行计划进入了plan baseline里;autopurge表示该执行计划是否为定期自动删除,YES表示是,NO表示否。
我们继续测试,在skew上添加一个索引,从而让原来的SQL不走全表扫描,而改走索引扫描。
SQL> create index idx_t1 on t1(skew); SQL> exec dbms_stats.gather_table_stats(user,'t1',cascade=>true); SQL> select * from t1 where skew=200; --索引扫描 SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge from dba_sql_plan_baselines where sql_text like 'select * from t1 where skew=200'; SIGNATURE SQL_HANDLE PLAN_NAME ORIGIN ENA ACC AUT ---------- ------------------------ ----------------------------- ----------- --- --- --- 1.2376E+19 SYS_SQL_abc0a2c042fa089c SYS_SQL_PLAN_42fa089c844cb98a AUTO-CAPTURE YES YES YES 1.2376E+19 SYS_SQL_abc0a2c042fa089c SYS_SQL_PLAN_42fa089cdbd90e8e AUTO-CAPTURE YES NO YES
这时我们可以看到,dba_sql_plan_baselines视图里多了一个执行计划,也就是我们后面那个使用了索引扫描的执行计划。而该执行计划的accepted为NO,说明该计划并没有进入plan baseline里,但是进入了plan history里。
这时,我们可以通过调用dbms_spm包来手工将走索引的执行计划加入到plan baseline里。如下所示,将accepted改为YES。
SQL> dbms_spm.alter_sql_plan_baseline( sql_handle => 'SYS_SQL_abc0a2c042fa089c', plan_name => 'SYS_SQL_PLAN_42fa089c844cb98a', attribute_name => 'ACCEPTED', attribute_value => 'YES');
然后再次查询dba_sql_plan_baselines视图,可以发现后面的执行计划的accepted变为了YES。
SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge from dba_sql_plan_baselines where sql_text like 'select * from t1 where skew=200'; SIGNATURE SQL_HANDLE PLAN_NAME ORIGIN ENA ACC AUT ---------- ------------------------ ----------------------------- ----------- --- --- --- 1.2376E+19 SYS_SQL_abc0a2c042fa089c SYS_SQL_PLAN_42fa089c844cb98a AUTO-CAPTURE YES YES YES 1.2376E+19 SYS_SQL_abc0a2c042fa089c SYS_SQL_PLAN_42fa089cdbd90e8e AUTO-CAPTURE YES YES YES
如果我们要手工删除plan baseline里的执行计划,则可以调用dbms_spm里的存储过程来实现。
SQL> var cnt number;
SQL> exec :cnt := dbms_spm.purge_sql_plan_baseline('SYS_SQL_abc0a2c042fa089c');
删除指定SQL语句的执行计划以后,再去查询dba_sql_plan_baselines就会发现上面测试SQL语句的执行计划不存在了。
从上面的描述可以看出,SQL Plan Management特性的主要作用就是通过引入一个SQL plan baseline,从而保证SQL语句执行计划的稳定,进而保证系统性能的稳定。本质上,它属于11g之前的存储大纲的升级版,而且是自动实现的,不需要人工干预。