从上述显示可以看出,现在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_NAME OBJECT_ID
------------------------------ ----------
TAB$ 4
zx@MYDB>select * from table(dbms_xplan.display_cursor(null,null,'advanced'));
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 0n5z3wmf8qpgn, 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.