,也就是accepted为YES的执行计划为v_id等于12462得到的,而第二个执行计划,也就是accepted为NO的是由v_id等于1得到的。第二个执行计划还没有被加入plan baseline,所以优化器不会使用该执行计划。我们将第二个执行计划的accepted改为YES,从而让oracle考虑使用该计划。
hr@ora11g > var cnt number;
hr@ora11g > begin
2 :cnt := dbms_spm.alter_sql_plan_baseline(
3 sql_handle => 'SYS_SQL_ea05bbed6f2f670c',
4 plan_name => 'SYS_SQL_PLAN_6f2f670cdbd90e8e',
5 attribute_name => 'ACCEPTED', attribute_value => 'YES');
6 end;
7 /
我们来看一下这两个执行计划分别是怎样的。
注意:在这里我们要验证oracle会为不同绑定变量生成不同的执行计划时,不能使用set autotrace traceonly exp stat等其他方式。因为set autotrace得出的执行计划始终都是第一次生成的执行计划。我们通过plan baseline从侧面来验证它。当然,我们也可以通过设置sql_trace=true从而将执行计划转储出来进行验证。
SQL> select * from table(dbms_xplan.display_sql_plan_baseline
2 ('SYS_SQL_ea05bbed6f2f670c','SYS_SQL_PLAN_6f2f670c844cb98a'));
......
--------------------------------------------------------------------------------
Plan hash value: 50753647
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 126 | 2 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 6 | 126 | 2 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_T1 | 6 | | 1 (0)| 00:00:01 |
-----------------------------------------------------------------------------------
......
SQL> select * from table(dbms_xplan.display_sql_plan_baseline
2 ('SYS_SQL_ea05bbed6f2f670c','SYS_SQL_PLAN_6f2f670cdbd90e8e'));
......
--------------------------------------------------------------------------------
Plan hash value: 3617692013
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU) | Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 6 | 126 | 16 (0) | 00:00:01 |
|* 1 | TABLE ACCESS FULL | T1 | 6 | 126 | 16 (0) | 00:00:01 |
--------------------------------------------------------------------------
......
很明显,第一个是索引扫描,第二个是全表扫描。同样,我们来看一下v$sql里该sql语句有几条记录。
hr@ora11g > select sql_text,sql_id,child_number,plan_hash_value
2 from v$sql where sql_text like 'select * from t1 where%';
SQL_TEXT SQL_ID CHILD_NUMBER PLAN_HASH_VALUE
--------------------------------- ------------- ------------ ----------------
select * from t1 where id=:v_id 7y7tt6xyhas1g 0 50753647
可以看到,该SQL语句目前在内存里只存在一个执行计划,其plan hash value就等于我们在前面plan baseline里看到的第一个走索引的执行计划的hash value。我们把该执行计划显示出来进行确认。
hr@ora11g > select * from table(dbms_xplan.display_cursor('7y7tt6xyhas1g',0));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------
SQL_ID 7y7tt6xyhas1g, child number 0
-------------------------------------
select * from t1 where id=:v_id
Plan hash value: 50753647
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
| 0 | SELECT STATEMENT | | | | 2 (100) | |
| 1 | TABLE ACCESS BY INDEX ROWID| T1 | 1 | 21 | 2 (0) | 00:00:01 |
|* 2 | INDEX RANGE SCAN | IDX_T1 | 1 | | 1 (0) | 00:00:01 |
......
结果很明显,正是走索引的执行计划。然后我们继续为帮定变量传入1,多执行几次。
hr@ora11g > exec :v_id := 1;
hr@ora11g > set autotrace traceon