Chinaunix首页 | 论坛 | 博客
  • 博客访问: 245331
  • 博文数量: 50
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 533
  • 用 户 组: 普通用户
  • 注册时间: 2015-07-28 21:56
个人简介

活着,寻找生存。

文章分类

全部博文(50)

文章存档

2017年(1)

2016年(20)

2015年(29)

我的朋友

分类: Oracle

2015-11-21 18:10:44

Oracle 使用SPM来稳定执行计划示例–手工生成SPM
 
使用手工生成sql plan baseline,在不改变目标sql文本的情况下调整其执行计划,其思路也是“偷梁换柱”,具体步骤为:
    
(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)使用dbms_spm.drop_plan_baseline删除在步骤(1)中手工生成的原目标sql的初始执行计划所对应的sql plan baseline。此时,使用dbms_spm.drop_plan_baseline传入的参数为如下所示:
    dbms_spm.drop_plan_baseline
   ( 
       sql_handle=>’原目标sql在步骤(1)中所产生的sql plan baseline的sql_handle’,
       plan_name=>’原目标sql在步骤(1)中所产生的sql plan baseline的plan_name'
     )
  
我们来看一个利用手工生成的sql plan baseline,在不改变目标sql的sql文本的情况下更改其执行计划的实例。先执行如下sql(这里使用了hint强制不使用索引idx_cs,以模拟哪些执行计划错误的sql):
  
23:51:15 SQL> select /*+no_index(cap_spm,idx_cs) */ object_name,object_id from cap_spm where object_id=4;
  
OBJECT_NAME                                                              OBJECT_ID
-------------------------------------------------------------------------------------------------------------------------------- ----------
TAB$                                                                      4
  
Elapsed: 00:00:00.03
    
其执行计划如下:
    
23:52:16 SQL> select * from table(dbms_xplan.display_cursor(null,null,'advanced'));
  
PLAN_TABLE_OUTPUT
----------------------------------------------------
SQL_ID    1h04bpbyrqxwb, child number 0
-------------------------------------
select /*+no_index(cap_spm,idx_cs) */ object_name,object_id from
cap_spm where object_id=4
  
Plan hash value: 619725477
  
-----------------------------------------------------------------------------
| Id  | Operation      | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |        |        |        |    297 (100)|        |
|*  1 |  TABLE ACCESS FULL| CAP_SPM |      1 |     30 |    297   (1)| 00:00:04 |
-----------------------------------------------------------------------------
  
从上述显示内容中可以看到,现在目标sql的执行计划走的是对表cap_spm的全部扫描,其sql_id为1h04bpbyrqxwb,plan hash value为619725477。
  
现在没有开启sql plan baseline的自动捕获,从如下查询结果中可以看出,目标sql确实没有对应的sql plan baseline:
  
23:52:25 SQL> select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+no_index(cap_spm,idx_cs) */ object_name,object_id from cap_spm where object_id=4';
  
no rows selected
  
Elapsed: 00:00:00.02
  
使用目标sql的初始执行计划(即对表cap_spm的全部扫描)所对应的sql_id和plan hash value来手工生成对应的sql plan baseline:
  
23:56:40 SQL> var temp number
23:59:53 SQL> exec :temp:=dbms_spm.load_plans_from_cursor_cache(sql_id=>'1h04bpbyrqxwb',plan_hash_value=>619725477);
  
PL/SQL procedure successfully completed.
  
Elapsed: 00:00:00.19
  
从如下查询结果中可以看出,目标sql的初始执行计划所对应的sql plan baseline 已经成功生成,其对应的sql_handle 为SQL_0f62435374ae89c3,plan_name为SQL_PLAN_0ysk3aduax2f3f4dd99e6:
  
00:00:29 SQL> select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+no_index(cap_spm,idx_cs) */ object_name,object_id from cap_spm where object_id=4';
  
SQL_HANDLE               PLAN_NAME              ORIGIN         ENA ACC SQL_TEXT
------------------------------ ------------------------------ -------------- --- --- --------------------------------------------------------------------------------
SQL_0f62435374ae89c3           SQL_PLAN_0ysk3aduax2f3f4dd99e6 MANUAL-LOAD    YES YES select /*+no_index(cap_spm,idx_cs) */ object_name,object_id
                                             from cap_spm where o
  
Elapsed: 00:00:00.00
   
改写原目标sql,加入强制走索引idx_cs的hint后重新执行:
   
00:02:17 SQL> select /*+index(cap_spm,idx_cs) */ object_name,object_id from cap_spm where object_id=4;
  
OBJECT_NAME                                                              OBJECT_ID
-------------------------------------------------------------------------------------------------------------------------------- ----------
TAB$                                                                      4
  
Elapsed: 00:00:00.00
  
其执行计划如下:
  
00:04:04 SQL> select * from table(dbms_xplan.display_cursor(null,null,'advanced'));
  
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------
SQL_ID    4y6khahh4k16x, child number 0
-------------------------------------
select /*+index(cap_spm,idx_cs) */ object_name,object_id from cap_spm
where object_id=4
  
Plan hash value: 3149005651
  
---------------------------------------------------------------------------------------
| Id  | Operation            | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |          |       |       |   317 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| CAP_SPM |     1 |    30 |   317    (0)| 00:00:04 |
|*  2 |   INDEX RANGE SCAN        | IDX_CS  |     1 |       |     1    (0)| 00:00:01 |
---------------------------------------------------------------------------------------
  
从上述显示内容中可以看到,现在该sql的执行计划已经如我们所愿:从对表CAP_SPM的全表扫描变成了对索引IDX_CS的索引范围扫描,改写后的sql其sql_id为4y6khahh4k16x,Plan hash value:为3149005651。
  
 从如下查询结果可以看出,原目标sql现在依然只有其原执行计划(即对表CAP_SPM的全部扫描)所对应的sql plan baseline:
  
00:04:13 SQL> select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+no_index(cap_spm,idx_cs) */ object_name,object_id from cap_spm where object_id=4';
  
SQL_HANDLE               PLAN_NAME              ORIGIN         ENA ACC SQL_TEXT
------------------------------ ------------------------------ -------------- --- --- --------------------------------------------------------------------------------
SQL_0f62435374ae89c3           SQL_PLAN_0ysk3aduax2f3f4dd99e6 MANUAL-LOAD    YES YES select /*+no_index(cap_spm,idx_cs) */ object_name,object_id
                                             from cap_spm where o
  
Elapsed: 00:00:00.00
  
用上述改写后的sql的新执行计划(即对索引idx_cs的索引范围扫描)所对应的sql id和plan hash value 以及原目标sql的sql plan baseline的sql_handle来手工生成新的sql plan baseline:
  
00:08:18 SQL> exec :temp:=dbms_spm.load_plans_from_cursor_cache(sql_id=>'4y6khahh4k16x',plan_hash_value=>3149005651,sql_handle=>'SQL_0f62435374ae89c3');
  
PL/SQL procedure successfully completed.
  
Elapsed: 00:00:00.05
  
从如下查询结果中可以看出,改写过的sql的新执行计划所对应的sql plan baseline 已经成功生成。注意到所有手工生成的sql plan baseline的enabled和accepted的值均为“yes”,这是和自动捕获的sql plan baseline不一样的地方:
  
00:11:28 SQL> select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+no_index(cap_spm,idx_cs) */ object_name,object_id from cap_spm where object_id=4';
  
SQL_HANDLE               PLAN_NAME              ORIGIN         ENA ACC SQL_TEXT
------------------------------ ------------------------------ -------------- --- --- --------------------------------------------------------------------------------
SQL_0f62435374ae89c3           SQL_PLAN_0ysk3aduax2f3d7d172c1 MANUAL-LOAD    YES YES select /*+no_index(cap_spm,idx_cs) */ object_name,object_id
                                             from cap_spm where o
  
SQL_0f62435374ae89c3           SQL_PLAN_0ysk3aduax2f3f4dd99e6 MANUAL-LOAD    YES YES select /*+no_index(cap_spm,idx_cs) */ object_name,object_id
                                             from cap_spm where o
  
Elapsed: 00:00:00.01
  
drop掉原执行计划(即对表cap_spm的全表扫描)所对应的sql plan baseline:
  
00:16:24 SQL> exec :temp:=dbms_spm.drop_sql_plan_baseline(sql_handle=>'SQL_0f62435374ae89c3',plan_name=>'SQL_PLAN_0ysk3aduax2f3f4dd99e6');
  
PL/SQL procedure successfully completed.
  
Elapsed: 00:00:00.04
  
从如下查询结果中可以看出,现在只剩下了改写过的sql所对应的新执行计划所对应的sql plan baseline:
  
00:16:43 SQL> select sql_handle,plan_name,origin,enabled,accepted,sql_text from dba_sql_plan_baselines where sql_text like 'select /*+no_index(cap_spm,idx_cs) */ object_name,object_id from cap_spm where object_id=4';
  
SQL_HANDLE               PLAN_NAME              ORIGIN         ENA ACC SQL_TEXT
------------------------------ ------------------------------ -------------- --- --- --------------------------------------------------------------------------------
SQL_0f62435374ae89c3           SQL_PLAN_0ysk3aduax2f3d7d172c1 MANUAL-LOAD    YES YES select /*+no_index(cap_spm,idx_cs) */ object_name,object_id
                                             from cap_spm where o
  
Elapsed: 00:00:00.01
  
再次执行原目标sql: 
  
00:18:54 SQL> select /*+no_index(cap_spm,idx_cs) */ object_name,object_id from cap_spm where object_id=4;
  
OBJECT_NAME                                                              OBJECT_ID
-------------------------------------------------------------------------------------------------------------------------------- ----------
TAB$                                                                      4
  
Elapsed: 00:00:00.01
   
其执行计划如下:
   
00:19:00 SQL> select * from table(dbms_xplan.display_cursor(null,null,'advanced'));
  
PLAN_TABLE_OUTPUT
------------------------------------------------------------
SQL_ID    1h04bpbyrqxwb, child number 2
-------------------------------------
select /*+no_index(cap_spm,idx_cs) */ object_name,object_id from
cap_spm where object_id=4
  
Plan hash value: 3149005651
  
---------------------------------------------------------------------------------------
| Id  | Operation            | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT        |          |       |       |   317 (100)|          |
|   1 |  TABLE ACCESS BY INDEX ROWID| CAP_SPM |     1 |    30 |   317    (0)| 00:00:04 |
|*  2 |   INDEX RANGE SCAN        | IDX_CS  |     1 |       |     1    (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
。。。。。。。。。
Note
-----
   - SQL plan baseline SQL_PLAN_0ysk3aduax2f3d7d172c1 used for this statement
  
50 rows selected.
  
Elapsed: 00:00:00.05
从上述显示内容中可以看出,现在原目标sql的执行计划已经从对表cap_spm的全部扫描变为了对索引idx_cs的索引范围扫描。注意到上述执行计划中的note部分有如下内容:“SQL plan baseline SQL_PLAN_0ysk3aduax2f3d7d172c1 used for this statement”,这表明改写后的sql的新执行计划(即对索引idx_cs的索引范围扫描)所对应的sql plan baseline已经被oracle成功应用到了原目标sql上,“偷梁换柱”的过程已经成功完成。这里我们已经用手工生成的sql plan baseline成功实现了在不改变目标sql的sql文本的情况下更改其执行计划的目的。

参考文献:【基于oracle的sql优化】---崔华
阅读(1364) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~