您的位置:首页 > 数据库

使用SQL Plan Baselines影响已加入hints的SQL执行计划

2016-07-08 08:55 441 查看

reference                            DBA手记2

        

1.SQL Plan Baseline(执行计划基线)概论

 

    如果应用程序中强行加了hints(提示),可以使用SQL Profile来稳定执行计划,除了使用SQL Profile方式,还可以使用SQL Plan Baseline(执行计划基线),该特性从11g开始支持,同时取代了10g之前的stored outline功能,因为stored outline(存储提纲)不够智能,而且其操作也比较繁琐。

 

主要作用:

    稳定给定SQL语句的执行计划,防止执行环境或对象统计信息等等因子的改变对SQL语句的执行计划产生影响!

     减少数据库中出现SQL语句性能退化的概率,理论上不允许一条语句切换到一个比已经执行过的执行计划慢很多的新的执行计划上!

    SQL执行计划基线保存在数据字典中,查询优化器会自动判断使用他们。

 

    SQL Plan Baseline可以通过脚本或图形界面方式来配置管理,这里使用脚本完成,即调用dbms_spm。

 

2.创建测试表,并收集统计信息

select sql_handle,plan_name,dbms_lob.substr(sql_text,60,1) sql_text,ACCEPTED from dba_sql_plan_baselines;

alter system flush shared_pool;

 

sys@ORCL>create table big_table as select rownum as id,t.* from all_objects t;

Table created.

sys@ORCL>create index idx_big_table_id on big_table(id);

Index created.

sys@ORCL>exec dbms_stats.gather_table_stats(user,'big_table');

PL/SQL procedure successfully completed.

 

3.执行查询测试

sys@ORCL>set autotrace on explain

sys@ORCL>select count(*) from big_table where id between 100 and 200;

  COUNT(*)

----------

       101

Execution Plan

----------------------------------------------------------

Plan hash value: 2068851779

--------------------------------------------------------------------------------------

| Id  | Operation         | Name             | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |                  |     1 |     5 |     2   (0)| 00:00:01 |

|   1 |  SORT AGGREGATE   |                  |     1 |     5 |            |          |

|*  2 |   INDEX RANGE SCAN| IDX_BIG_TABLE_ID |   102 |   510 |     2   (0)| 00:00:01 |

--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("ID">=100 AND "ID"<=200)

 

4.强行加入full hints使其变为全表扫描

sys@ORCL>select /*+full(t)*/ count(*) from big_table t where id between 100 and 200;

  COUNT(*)

----------

       101

Execution Plan

----------------------------------------------------------

Plan hash value: 599409829

--------------------------------------------------------------------------------

| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |           |     1 |     5 |   345   (1)| 00:00:05 |

|   1 |  SORT AGGREGATE    |           |     1 |     5 |            |          |

|*  2 |   TABLE ACCESS FULL| BIG_TABLE |   102 |   510 |   345   (1)| 00:00:05 |

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - filter("ID"<=200 AND "ID">=100)

 

5.启用SQL Plan Baselines自动获取

----利用SQL Plan Baselines获取更优的执行计划

sys@ORCL>set autot off

 

sys@ORCL>show parameter optimizer_use_sql_plan_baselines

NAME                                 TYPE                   VALUE

------------------------------------ ---------------------- ------------------------------

optimizer_use_sql_plan_baselines     boolean                TRUE

 

sys@ORCL>select /*+full(t)*/ count(*) from big_table t where id between 100 and 200;

  COUNT(*)

----------

       101

 

sys@ORCL>select * from table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT

----------------------------------------------------------------------------------------------------

SQL_ID  9babjv8yq8ru3, child number 0

BEGIN DBMS_OUTPUT.GET_LINES(:LINES, :NUMLINES); END;

NOTE: cannot fetch plan for SQL_ID: 9babjv8yq8ru3, CHILD_NUMBER: 0

      Please verify value of SQL_ID and CHILD_NUMBER;

      It could also be that the plan is no longer in cursor cache (check v$sql_plan)

8 rows selected.

 

sys@ORCL>set serveroutput off

 

sys@ORCL>select /*+full(t)*/ count(*) from big_table t where id between 100 and 200;

sys@ORCL>select /*+full(t)*/ count(*) from big_table t where id between 100 and 200;

 

sys@ORCL>select * from table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT

----------------------------------------------------------------------------------------------------

SQL_ID  84nabsvnwf9kb, child number 0

-------------------------------------

select /*+full(t)*/ count(*) from big_table t where id between 100 and

200

Plan hash value: 599409829

--------------------------------------------------------------------------------

| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |           |       |       |   345 (100)|          |

|   1 |  SORT AGGREGATE    |           |     1 |     5 |            |          |

|*  2 |   TABLE ACCESS FULL| BIG_TABLE |   102 |   510 |   345   (1)| 00:00:05 |

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - filter(("ID"<=200 AND "ID">=100))

20 rows selected.

 

 

DECLARE 

  l_plans_loaded  PLS_INTEGER;

 BEGIN

   l_plans_loaded := DBMS_SPM.load_plans_from_cursor_cache(sql_id => '84nabsvnwf9kb',plan_hash_value=>null);

 END;

 /

 

6.修改基线

----查看对应的sql_handle,以便用新的执行计划替换

select sql_handle,plan_name,dbms_lob.substr(sql_text,60,1) sql_text,ACCEPTED from dba_sql_plan_baselines;

SQL_HANDLE      PLAN_NAME   SQL_TEXT   ACCEPT

----------------- -------------------------- ------------------------ ---------------------------------

SQL_17dc586bdecfee90      SQL_PLAN_1gr2sdggczvnhc74815fa  select /*+full(t)*/ count(*) from big_table t where id betwe   YES

 

----执行不加hint的sql,使用dbms_spm从library cache中加载该执行计划

sys@ORCL>select count(*) from big_table t where id between 100 and 200;

  COUNT(*)

----------

       101

 

sys@ORCL>select prev_sql_id from v$session where sid=userenv('sid');

PREV_SQL_ID

--------------------------

1zy136qv3g3k9

 

sys@ORCL>select * from table(dbms_xplan.display_cursor(sql_id => '1zy136qv3g3k9'));

PLAN_TABLE_OUTPUT

----------------------------------------------------------------------------------------------------

SQL_ID  1zy136qv3g3k9, child number 0

-------------------------------------

select count(*) from big_table t where id between 100 and 200

Plan hash value: 2068851779

--------------------------------------------------------------------------------------

| Id  | Operation         | Name             | Rows  | Bytes | Cost (%CPU)| Time    

--------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |                  |       |       |     2 (100)|          |

|   1 |  SORT AGGREGATE   |                  |     1 |     5 |            |          |

|*  2 |   INDEX RANGE SCAN| IDX_BIG_TABLE_ID |   102 |   510 |     2   (0)| 00:00:01

--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("ID">=100 AND "ID"<=200)

19 rows selected.

 

----修改基线

var rtn number

exec :rtn :=dbms_spm.load_plans_from_cursor_cache(sql_id =>'1zy136qv3g3k9',sql_handle => 'SQL_17dc586bdecfee90');

 

sys@ORCL>select sql_handle,plan_name,dbms_lob.substr(sql_text,60,1) sql_text,ACCEPTED from dba_sql_plan_baselines;

SQL_HANDLE     PLAN_NAME    SQL_TEXT   ACCEPT

------------   --------------  --------------------------     -----------------------

SQL_17dc586bdecfee90           SQL_PLAN_1gr2sdggczvnhc41cefbc

select /*+full(t)*/ count(*) from big_table t where id betwe

YES

SQL_17dc586bdecfee90           SQL_PLAN_1gr2sdggczvnhc74815fa

select /*+full(t)*/ count(*) from big_table t where id betwe

YES

 

sys@ORCL>select /*+full(t)*/ count(*) from big_table t where id between 100 and 200;

sys@ORCL>select /*+full(t)*/ count(*) from big_table t where id between 100 and 200;

 

sys@ORCL>select * from table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT

----------------------------------------------------------------------------------------------------

SQL_ID  84nabsvnwf9kb, child number 0

-------------------------------------

select /*+full(t)*/ count(*) from big_table t where id between 100 and

200

Plan hash value: 599409829

--------------------------------------------------------------------------------

| Id  | Operation          | Name      | Rows  | Bytes | Cost (%CPU)| Time     |

--------------------------------------------------------------------------------

|   0 | SELECT STATEMENT   |           |       |       |   345 (100)|          |

|   1 |  SORT AGGREGATE    |           |     1 |     5 |            |          |

|*  2 |   TABLE ACCESS FULL| BIG_TABLE |   102 |   510 |   345   (1)| 00:00:05 |

--------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - filter(("ID"<=200 AND "ID">=100))

Note

-----

   - SQL plan baseline SQL_PLAN_1gr2sdggczvnhc74815fa used for this statement

24 rows selected.

 

7.删除原有基线

select sql_handle,plan_name,dbms_lob.substr(sql_text,60,1) sql_text,ACCEPTED from dba_sql_plan_baselines;

 

sys@ORCL>var rtn number

sys@ORCL>exec :rtn :=dbms_spm.drop_sql_plan_baseline(plan_name => 'SQL_PLAN_1gr2sdggczvnhc74815fa');

 

sys@ORCL>select /*+full(t)*/ count(*) from big_table t where id between 100 and 200;

sys@ORCL>select /*+full(t)*/ count(*) from big_table t where id between 100 and 200;

 

sys@ORCL>select * from table(dbms_xplan.display_cursor);

PLAN_TABLE_OUTPUT

----------------------------------------------------------------------------------------------------

SQL_ID  84nabsvnwf9kb, child number 1

-------------------------------------

select /*+full(t)*/ count(*) from big_table t where id between 100 and

200

Plan hash value: 2068851779

--------------------------------------------------------------------------------------

| Id  | Operation         | Name             | Rows  | Bytes | Cost (%CPU)| Time    

--------------------------------------------------------------------------------------

|   0 | SELECT STATEMENT  |                  |       |       |     2 (100)|         

|   1 |  SORT AGGREGATE   |                  |     1 |     5 |            |         

|*  2 |   INDEX RANGE SCAN| IDX_BIG_TABLE_ID |   102 |   510 |     2   (0)| 00:00:01

--------------------------------------------------------------------------------------

Predicate Information (identified by operation id):

---------------------------------------------------

   2 - access("ID">=100 AND "ID"<=200)

Note

-----

   - SQL plan baseline SQL_PLAN_1gr2sdggczvnhc41cefbc used for this statement

24 rows selected.

 

    所以,当我们在无法改变应用程序的sql语句时,可以利用sql plan baselines 来影响其执行计划。

 

 

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30130773/viewspace-2121696/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30130773/viewspace-2121696/

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: