Implementing Hints through Baseline
Posted by Sumit on June 11, 2011
Baselines
SQL Plan Management(SPM) provides a mechanism to prevent unwanted plan flips.
Whenever a query is hard parsed, oracle produces several execution plan and compares it with the accepted plan in a baseline. If a match is found, oracle picks that plan.
The behaviour of baseline is governed by 2 parameters.
- Optimizer_capture_sql_plan_baselines
- Optimizer_use_sql_plan_baseline
optimizer_capture_sql_plan_baseline if set to true, let oracle automatically capture sql plan baselines. The default value is false
Optimizer_use_sql_plan_baseline, if set to true, force oracle to use the sql plan baseline (if present). The default is true.
Implementing HINTS without changing code
Environment Setting :-
- Optimizer_capture_sql_plan_baselines (false)
- Optimizer_use_sql_plan_baseline (true)
Session1>desc mytab Name Null? Type ----------------------------------------- -------- ---------------------------- OWNER VARCHAR2(30) OBJECT_NAME VARCHAR2(128) SUBOBJECT_NAME VARCHAR2(30) OBJECT_ID NUMBER DATA_OBJECT_ID NUMBER OBJECT_TYPE VARCHAR2(19) CREATED DATE LAST_DDL_TIME DATE TIMESTAMP VARCHAR2(19) STATUS VARCHAR2(7) TEMPORARY VARCHAR2(1) GENERATED VARCHAR2(1) SECONDARY VARCHAR2(1) NAMESPACE NUMBER EDITION_NAME VARCHAR2(30)
Step 1> Query the mytab table without index.
select /*+woindex */ * from mytab where GENERATED='FOR';
no rows selected
SELECT * FROM TABLE(dbms_xplan.display_cursor('0ytzpgnhg1g83'));
SQL_ID 0ytzpgnhg1g83, child number 0
-------------------------------------
select /*+woindex */ * from mytab where GENERATED='FOR'
Plan hash value: 96696846
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 124K(100)| |
|* 1 | TABLE ACCESS FULL| MYTAB | 4819K| 422M| 124K (3)| 00:24:54 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("GENERATED"='FOR')
select sql_text, sql_handle, plan_name, enabled, accepted from dba_sql_plan_baselines;
no rows selected
Step 2> No baseline yet exists for the current query. Lets baseline the plan to make sure it does not pick index automatically so that we can simulate the test.
var v_num number; exec :v_num:=dbms_spm.load_plans_from_cursor_cache(sql_id => '0ytzpgnhg1g83',plan_hash_value => 96696846 ); PL/SQL procedure successfully completed. select sql_text, sql_handle, plan_name, enabled, accepted from dba_sql_plan_baselines; SQL_TEXT SQL_HANDLE PLAN_NAME ENA ACC -------------------------------------------------------------------------------- ------------------------------ ------------------------------ --- --- select /*+woindex */ * from mytab where GENERATED='FOR' SYS_SQL_50969e88fdd635aa SYS_SQL_PLAN_fdd635aada00620d YES YES 1 row selected.
Step 3> Lets create an index
create index mytab_idx2 on mytab(GENERATED) parallel 4; Index created. alter index mytab_idx2 noparallel; Index altered.
Step4> Execute the query to confirm its not using the index since optimizer_use_sql_plan_baseline is set to true.
select * FROM TABLE(dbms_xplan.display_cursor('0ytzpgnhg1g83',1));
PLAN_TABLE_OUTPUT
------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID 0ytzpgnhg1g83, child number 1
-------------------------------------
select /*+woindex */ * from mytab where GENERATED='FOR'
Plan hash value: 96696846
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 124K(100)| |
|* 1 | TABLE ACCESS FULL| MYTAB | 4819K| 422M| 124K (3)| 00:24:54 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("GENERATED"='FOR')
Note
-----
- SQL plan baseline SYS_SQL_PLAN_fdd635aada00620d used for this statement
22 rows selected.
Step5>Execute the query with index hint and create the baseline.
select /*+index(mytab_idx2 mytab) */ * from mytab where GENERATED='FOR';
no rows selected
Select * FROM TABLE(dbms_xplan.display_cursor('ay757nb7anm56'));
PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------
SQL_ID ay757nb7anm56, child number 0
-------------------------------------
select /*+index(mytab_idx2 mytab) */ * from mytab where GENERATED='FOR'
Plan hash value: 3007699452
------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 995 (100)| |
| 1 | TABLE ACCESS BY INDEX ROWID| MYTAB | 4819K| 422M| 995 (1)| 00:00:12 |
|* 2 | INDEX RANGE SCAN | MYTAB_IDX2 | 4896K| | 90 (2)| 00:00:02 |
------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("GENERATED"='FOR')
19 rows selected.
exec :v_num:=dbms_spm.load_plans_from_cursor_cache(sql_id => 'ay757nb7anm56',plan_hash_value => '3007699452' );
select sql_text, sql_handle, plan_name, enabled, accepted from dba_sql_plan_baselines;
SQL_TEXT SQL_HANDLE PLAN_NAME ENA ACC
-------------------------------------------------------------------------------- ------------------------------ ------------------------------ --- ---
select /*+woindex */ * from mytab where GENERATED='FOR' SYS_SQL_50969e88fdd635aa SYS_SQL_PLAN_fdd635aa041dae64 YES NO
select /*+woindex */ * from mytab where GENERATED='FOR' SYS_SQL_50969e88fdd635aa SYS_SQL_PLAN_fdd635aada00620d YES YES
select /*+index(mytab_idx2 mytab) */ * from mytab where GENERATED='FOR' SYS_SQL_5229297eca7bb2c7 SYS_SQL_PLAN_ca7bb2c7041dae64 YES YES
3 rows selected.
Step6> Now here, you can see that plan(SYS_SQL_PLAN_fdd635aa041dae64 ) being automatically linked with sql_handle (SYS_SQL_50969e88fdd635aa).
You can accept it.
In case, plan is not linked with sql_handle, use the below method to link plan manually.
exec :v_num:=dbms_spm.load_plans_from_cursor_cache(sql_id => 'ay757nb7anm56',plan_hash_value => 3007699452 ,sql_handle => 'SYS_SQL_50969e88fdd635aa'); select sql_text, sql_handle, plan_name, enabled, accepted from dba_sql_plan_baselines; SQL_TEXT SQL_HANDLE PLAN_NAME ENA ACC -------------------------------------------------------------------------------- ------------------------------ ------------------------------ --- --- select /*+woindex */ * from mytab where GENERATED='FOR' SYS_SQL_50969e88fdd635aa SYS_SQL_PLAN_fdd635aa041dae64 YES YES select /*+woindex */ * from mytab where GENERATED='FOR' SYS_SQL_50969e88fdd635aa SYS_SQL_PLAN_fdd635aada00620d YES YES select /*+index(mytab_idx2 mytab) */ * from mytab where GENERATED='FOR' SYS_SQL_5229297eca7bb2c7 SYS_SQL_PLAN_ca7bb2c7041dae64 YES YES 3 rows selected.
dbms_spm.load_plans_from_cursor_cache(sql_id => ‘<hinted_sqlid>’,plan_hash_value=><hinted_plan_value>,sql_handle=>’<sql handle of original query>’)

Baselines–Part II « For DBA said
[...] my previous post, I had described how to implement hints through baselines without changing code. Also, I touched [...]
SPM & Profiles-Part 1 « For DBA said
[...] Implementing Hints through Baseline [...]