在遭遇执行计划不稳定或者执行计划错误的情况下,通过baseline来固定SQL执行计划以确保执行计划稳定性、提高性能。baseline是oracle 11G提供的稳固sql执行计划的功能,是spm功能的一部分。
步骤如下:
- SQL> set linesize 1000
- SQL> col index_name for a40
- SQL> col COLUMN_NAME for a20
- SQL> select index_name,COLUMN_NAME from dba_ind_columns where table_name='TEST_PART' and table_owner='TEST_DBA';
- INDEX_NAME COLUMN_NAME
- ---------------------------------------- --------------------
- IND_PART_DT DT
- SQL>
- 此表由索引,可以测试走做引以及走全表扫描
- SQL> set autotrace on explain
- SQL> set pagesize 300
- SQL> set linesize 300
- SQL> var name1 varchar2(10);
- SQL> var name2 varchar2(100);
- SQL> var name1 varchar2(100);
- SQL> exec :name1 :='2012-09-21 8:05:55';
- PL/SQL procedure successfully completed.
- SQL> exec :name2 :='2012-09-21 8:06:05';
- PL/SQL procedure successfully completed.
- SQL> select * from TEST_DBA.TEST_PART where dt>=to_date(:name1,'yyyy-mm-dd hh24:mi:ss') and
- 2 dt<to_date(:name2,'yyyy-mm-dd hh24:mi:ss') ;
- ID STR DT
- ---------- ---------- ---------
- 29155 aaaaaaaaa 21-SEP-12
- 29156 aaaaaaaaa 21-SEP-12
- 29157 aaaaaaaaa 21-SEP-12
- 29158 aaaaaaaaa 21-SEP-12
- 29159 aaaaaaaaa 21-SEP-12
- 29160 aaaaaaaaa 21-SEP-12
- 29161 aaaaaaaaa 21-SEP-12
- 29162 aaaaaaaaa 21-SEP-12
- 29163 aaaaaaaaa 21-SEP-12
- 29164 aaaaaaaaa 21-SEP-12
- 10 rows selected.
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 2229598636
- -------------------------------------------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
- -------------------------------------------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 250 | 5750 | 5 (0)| 00:00:01 | | |
- |* 1 | FILTER | | | | | | | |
- | 2 | PARTITION RANGE ITERATOR | | 250 | 5750 | 5 (0)| 00:00:01 | KEY | KEY |
- | 3 | TABLE ACCESS BY LOCAL INDEX ROWID| TEST_PART | 250 | 5750 | 5 (0)| 00:00:01 | KEY | KEY |
- |* 4 | INDEX RANGE SCAN | IND_PART_DT | 450 | | 3 (0)| 00:00:01 | KEY | KEY |
- -------------------------------------------------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - filter(TO_DATE(:NAME1,'yyyy-mm-dd hh24:mi:ss')<TO_DATE(:NAME2,'yyyy-mm-dd hh24:mi:ss'))
- 4 - access("DT">=TO_DATE(:NAME1,'yyyy-mm-dd hh24:mi:ss') AND "DT"<TO_DATE(:NAME2,'yyyy-mm-dd
- hh24:mi:ss'))
- 以上生成了索引的执行sql
- SQL> select /*+FULL(TEST_PART)*/ * from TEST_DBA.TEST_PART where dt>=to_date(:name1,'yyyy-mm-dd hh24:mi:ss') and
- 2 dt<to_date(:name2,'yyyy-mm-dd hh24:mi:ss') ;
- ID STR DT
- ---------- ---------- ---------
- 29155 aaaaaaaaa 21-SEP-12
- 29156 aaaaaaaaa 21-SEP-12
- 29157 aaaaaaaaa 21-SEP-12
- 29158 aaaaaaaaa 21-SEP-12
- 29159 aaaaaaaaa 21-SEP-12
- 29160 aaaaaaaaa 21-SEP-12
- 29161 aaaaaaaaa 21-SEP-12
- 29162 aaaaaaaaa 21-SEP-12
- 29163 aaaaaaaaa 21-SEP-12
- 29164 aaaaaaaaa 21-SEP-12
- 10 rows selected.
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 1956636844
- -------------------------------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
- -------------------------------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 250 | 5750 | 161 (3)| 00:00:02 | | |
- |* 1 | FILTER | | | | | | | |
- | 2 | PARTITION RANGE ITERATOR| | 250 | 5750 | 161 (3)| 00:00:02 | KEY | KEY |
- |* 3 | TABLE ACCESS FULL | TEST_PART | 250 | 5750 | 161 (3)| 00:00:02 | KEY | KEY |
- -------------------------------------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - filter(TO_DATE(:NAME1,'yyyy-mm-dd hh24:mi:ss')<TO_DATE(:NAME2,'yyyy-mm-dd hh24:mi:ss'))
- 3 - filter("DT">=TO_DATE(:NAME1,'yyyy-mm-dd hh24:mi:ss') AND
- "DT"<TO_DATE(:NAME2,'yyyy-mm-dd hh24:mi:ss'))
- 以上是走全表扫描的执行计划
- 现在要将该语句全部变为走全表扫描,也就是用全表扫描的执行计划来绑定该语句
- SQL> select sql_id from v$sql_plan where plan_hash_value=2229598636;
- SQL_ID
- -------------
- day4zwzuhxjnd
- day4zwzuhxjnd
- day4zwzuhxjnd
- day4zwzuhxjnd
- day4zwzuhxjnd
- SQL> select sql_id from v$sql_plan where plan_hash_value=1956636844;
- SQL_ID
- -------------
- fzs1wktabj9ny
- fzs1wktabj9ny
- fzs1wktabj9ny
- fzs1wktabj9ny
- 进行绑定
- SQL> declare
- 2 m_clob clob;
- 3 begin
- 4 select sql_fulltext
- 5 into m_clob
- 6 from v$sql
- 7 where sql_id = 'day4zwzuhxjnd'
- 8 and child_number = 0;
- 9 dbms_output.put_line(m_clob);
- 10 dbms_output.put_line(dbms_spm.load_plans_from_cursor_cache(
- 11 sql_id => 'fzs1wktabj9ny',
- 12 plan_hash_value => 1956636844,
- 13 sql_text => m_clob,
- 14 fixed => 'YES',
- 15 enabled => 'YES'));
- 16 end;
- 17 /
- PL/SQL procedure successfully completed.
- 验证
- SQL> select * from TEST_DBA.TEST_PART where dt>=to_date(:name1,'yyyy-mm-dd hh24:mi:ss') and
- 2 dt<to_date(:name2,'yyyy-mm-dd hh24:mi:ss') ;
- ID STR DT
- ---------- ---------- ---------
- 29155 aaaaaaaaa 21-SEP-12
- 29156 aaaaaaaaa 21-SEP-12
- 29157 aaaaaaaaa 21-SEP-12
- 29158 aaaaaaaaa 21-SEP-12
- 29159 aaaaaaaaa 21-SEP-12
- 29160 aaaaaaaaa 21-SEP-12
- 29161 aaaaaaaaa 21-SEP-12
- 29162 aaaaaaaaa 21-SEP-12
- 29163 aaaaaaaaa 21-SEP-12
- 29164 aaaaaaaaa 21-SEP-12
- 10 rows selected.
- Execution Plan
- ----------------------------------------------------------
- Plan hash value: 1956636844
- -------------------------------------------------------------------------------------------------------
- | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
- -------------------------------------------------------------------------------------------------------
- | 0 | SELECT STATEMENT | | 250 | 5750 | 161 (3)| 00:00:02 | | |
- |* 1 | FILTER | | | | | | | |
- | 2 | PARTITION RANGE ITERATOR| | 250 | 5750 | 161 (3)| 00:00:02 | KEY | KEY |
- |* 3 | TABLE ACCESS FULL | TEST_PART | 250 | 5750 | 161 (3)| 00:00:02 | KEY | KEY |
- -------------------------------------------------------------------------------------------------------
- Predicate Information (identified by operation id):
- ---------------------------------------------------
- 1 - filter(TO_DATE(:NAME1,'yyyy-mm-dd hh24:mi:ss')<TO_DATE(:NAME2,'yyyy-mm-dd hh24:mi:ss'))
- 3 - filter("DT">=TO_DATE(:NAME1,'yyyy-mm-dd hh24:mi:ss') AND
- "DT"<TO_DATE(:NAME2,'yyyy-mm-dd hh24:mi:ss'))
- Note
- -----
- - SQL plan baseline "SQL_PLAN_c28fvkn3sbtbg70e51298" used for this statement
- SQL>
- 查看生成的sql baseline信息
- SQL> select signature,sql_handle,plan_name,origin,enabled,accepted,fixed,autopurge
- 2 from dba_sql_plan_baselines where sql_text like '%select * from TEST_DBA.TEST_PART%';
- SIGNATURE SQL_HANDLE PLAN_NAME ORIGIN ENA ACC FIX AUT
- ---------- ------------------------------ ------------------------------ -------------- --- --- --- ---
- 1.3917E+19 SQL_c121db950785e56f SQL_PLAN_c28fvkn3sbtbg70e51298 MANUAL-LOAD YES YES YES YES
- SQL>
- 如果不想要这个绑定计划了,则可以删除它
- declare
- l_pls number;
- begin
- l_pls := DBMS_SPM.DROP_SQL_PLAN_BASELINE(
- sql_handle => 'SQL_c121db950785e56f',
- plan_name => 'SQL_PLAN_c28fvkn3sbtbg70e51298'
- );
- end;
对于dbms_spm.load_plans_from_cursor_cache的说明
既然是from cursor的话那么要保证在执行过程中sql还是在内存里的不能被刷出去
declare
m_clob clob;
begin
select sql_fulltext
into m_clob
from v$sql
where sql_id = 'day4zwzuhxjnd'————–原始sql的 sql_id
and child_number = 0;—————–为了让sql只返回一行,也可以rownum=1代替
dbms_output.put_line(m_clob);
dbms_output.put_line(dbms_spm.load_plans_from_cursor_cache(
sql_id => 'fzs1wktabj9ny',————HINT SQL_ID
plan_hash_value => 1956636844,——————-HINT PLAN_HASH_VALUE
sql_text => m_clob,————————-原始SQL文本
fixed => 'YES', ———————禁止演化baseline
enabled => 'YES'));------生效
end;