Oracle 11g 执行计划管理2

1.创建测试数据

SQL> conn NC50/NC50
Connected.
SQL> create table tab1(id number,object_name varchar2(100));    
SQL> insert into tab1 select rownum,object_name from dba_objects;
SQL> commit;
SQL> set line 180
SQL> select * from tab1 where id=200;
SQL> select * from tab1 where id=200;

  尽管执行两次,但是这时去查询dba_sql_plan_baselines,试图找到SQL文本为select * from tab1 where id=200;的记录时,会发现没有记录,因为optimizer_capture_sql_plan_baselines缺省为false。我们将该参数设置为true以后继续测试

SQL> show parameter optimizer_capture_sql_plan_baselines

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
optimizer_capture_sql_plan_baselines boolean     FALSE
SQL> select * from dba_sql_plan_baselines where SQL_TEXT like '%tab1%';
no rows selected
SQL> 

2.开启自动捕获

SQL> alter session set optimizer_capture_sql_plan_baselines=true;
SQL> set line 180
SQL> set autotrace off
SQL> select * from tab1 where id=200;

        ID OBJECT_NAME
---------- ----------------------------------------------------------------------------------------------------
       200 SYS_LOB0000000207C00007$$

--查看对应的执行计划
SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge
  2  from dba_sql_plan_baselines 
  3  where sql_text like 'select * from tab1 where id=200';

 SIGNATURE SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENA ACC FIX AUT
---------- ------------------------------ ------------------------------ -------------- --- --- --- ---
8.3850E+18 SYS_SQL_745da4c2e5a4b97a       SQL_PLAN_78rd4sbku9fbuec7b7588 AUTO-CAPTURE   YES YES NO  YES

SQL>
可以看到,SQL语句在plan history里产生了一个执行计划。其中:
sql_handle表示SQL语句的句柄;
plan_name则表示该SQL的执行计划的名字;
origin表示该执行计划是如何进入plan history的,该列值为AUTO-CAPTURE则说明是由优化器自动加入的,如果为MANUAL则说明是由DBA手工加入的;
Enabled (控制活动):
  + YES (活动的,但不一定会被使用)
  + NO (可以理解为被标记删除)
Accepted(控制使用):
  + YES (只有 “Enabled” 并且“Accepted” 的计划才会被选择使用)
  + NO (如果是“Enabled” 那么只有被evolve成“Accepted”才有可能被执行)
Fixed(控制优先级):
  + YES (如果是“Enabled”并且“Accepted”,会优先选择这个计划,这个计划会被视为不需要改变的)
  + NO (普通的计划,无需优先)
autopurge表示该执行计划是否为定期自动删除,YES表示是,NO表示否。

  继续测试,在id上添加一个索引,从而让原来的SQL不走全表扫描,而改走索引扫描

SQL> create index idx_tab1 on tab1(id);
SQL> exec dbms_stats.gather_table_stats('NC50','tab1',cascade=>true);
SQL> select * from tab1 where id=200;

        ID OBJECT_NAME
---------- ----------------------------------------------------------------------------------------------------
       200 SYS_LOB0000000207C00007$$

SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge
  2  from dba_sql_plan_baselines 
  3  where sql_text like 'select * from tab1 where id=200';

 SIGNATURE SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENA ACC FIX AUT
---------- ------------------------------ ------------------------------ -------------- --- --- --- ---
8.3850E+18 SYS_SQL_745da4c2e5a4b97a       SQL_PLAN_78rd4sbku9fbu61724234 AUTO-CAPTURE   YES NO  NO  YES
8.3850E+18 SYS_SQL_745da4c2e5a4b97a       SQL_PLAN_78rd4sbku9fbuec7b7588 AUTO-CAPTURE   YES YES NO  YES

  这时我们可以看到,dba_sql_plan_baselines视图里多了一个执行计划,也就是我们后面那个使用了索引扫描的执行计划。而该执行计划的accepted为NO,说明该计划并没有进入plan baseline里,但是进入了plan history里。因为新生成的为不是ACCEPTED,所以不被启用。验证如下:

SQL> set autotrace traceonly explain
SQL> select * from tab1 where id=200;

Execution Plan
----------------------------------------------------------
Plan hash value: 2211052296

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |     1 |    28 |   112   (1)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| TAB1 |     1 |    28 |   112   (1)| 00:00:02 |
--------------------------------------------------------------------------

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

   1 - filter("ID"=200)

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

SQL>

  启用的执行计划不是高效的(SQL_PLAN_78rd4sbku9fbu61724234),而是全表扫描的(SQL_PLAN_78rd4sbku9fbuec7b7588)。启用高效的执行计划之前,需要
手动将执行计划演化成ACCEPTED

3.现将新生成的执行计划演化成ACCEPTED

SQL> set autotrace off
SQL> SELECT DBMS_SPM.evolve_sql_plan_baseline(sql_handle => 'SYS_SQL_745da4c2e5a4b97a') FROM   dual;
SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge
  2  from dba_sql_plan_baselines 
  3  where sql_text like 'select * from tab1 where id=200';

 SIGNATURE SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENA ACC FIX AUT
---------- ------------------------------ ------------------------------ -------------- --- --- --- ---
8.3850E+18 SYS_SQL_745da4c2e5a4b97a       SQL_PLAN_78rd4sbku9fbu61724234 AUTO-CAPTURE   YES YES NO  YES
8.3850E+18 SYS_SQL_745da4c2e5a4b97a       SQL_PLAN_78rd4sbku9fbuec7b7588 AUTO-CAPTURE   YES YES NO  YES

SQL>
 
--查看 当前所走的执行计划
SQL> set autotrace traceonly explain
SQL> select * from tab1 where id=200;
Execution Plan
----------------------------------------------------------
Plan hash value: 2722636538

----------------------------------------------------------------------------------------
| Id  | Operation                   | Name     | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |          |     1 |    28 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| TAB1     |     1 |    28 |     2   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | IDX_TAB1 |     1 |       |     1   (0)| 00:00:01 |
----------------------------------------------------------------------------------------

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

   2 - access("ID"=200)

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

SQL>

  结论:存在多个( “Enabled”“Accepted”)的计划时,选择cost最小的

4.删除Plans 和 Baselines

DECLARE
 l_plans_dropped  PLS_INTEGER;
BEGIN
 l_plans_dropped := DBMS_SPM.drop_sql_plan_baseline (
   sql_handle => 'SYS_SQL_745da4c2e5a4b97a',
   plan_name  => 'SQL_PLAN_78rd4sbku9fbu61724234');
   
 DBMS_OUTPUT.put_line(l_plans_dropped);
END;

SQL> set autotrace off
SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge
  2  from dba_sql_plan_baselines 
  3  where sql_text like 'select * from tab1 where id=200';

 SIGNATURE SQL_HANDLE                     PLAN_NAME                      ORIGIN         ENA ACC FIX AUT
---------- ------------------------------ ------------------------------ -------------- --- --- --- ---
8.3850E+18 SYS_SQL_745da4c2e5a4b97a       SQL_PLAN_78rd4sbku9fbuec7b7588 AUTO-CAPTURE   YES YES NO  YES

SQL> 

 

posted @ 2015-04-26 17:43  PoleStar  阅读(315)  评论(0编辑  收藏  举报