oracle利用INLIST ITERATOR优化SQL
2016-07-24 23:48
603 查看
开发人员反应一支查看bom的sql反应很慢,需要dba协助优化。
SQL如下:
SELECT A0.idA2A2,A0.updateCountA2,A0.classnameA2A2,ABS(NULL),A0.branchIdA2typeDefinitionRefe,A1.idA2A2,A1.updateCountA2,A1.idA3A6,A1.value FROM WTPartUsageLink A0,BooleanValue A1 WHERE (((A1.idA3A6 = :1 ) AND (A1.idA3A4 = A0.idA2A2) AND ((A1.idA3A5 = :2
) OR (A1.idA3A5 IS NULL )))) AND (A0.markForDeleteA2 = 0) AND (A0.idA2A2 IN (:3 ,:4 ,:5 ,:6 ,:7 ,:8 ,:9 ,:10 ,:11 ,:12 ,:13 ,:14 ,:15 ,:16 ,:17 ,:18 ,:19 ,:20 ,:21 ,:22 ,:23 ,:24 ,:25 ,:26 ,:27 ,:28 ,:29 ,:30 ,:31 ,:32 ,:33 ,:34 ,:35 ,:36 ,:37 ,:38 ,:39 ,:40
,:41 ,:42 ,:43 ,:44 ,:45 ,:46 ,:47 ,:48 ,:49 ,:50 ,:51 ,:52 ,:53 ,:54 ,:55 ,:56 ,:57 ,:58 ,:59 ,:60 ,:61 ,:62 ,:63 ,:64 ,:65 ,:66 ,:67 ,:68 ,:69 ,:70 ,:71 ,:72 ,:73 ,:74 ,:75 ,:76 ,:77 ,:78 ,:79 ,:80 ,:81 ,:82 ,:83 ,:84 ,:85 ,:86 ,:87 ,:88 ,:89 ,:90 ,:91 ,:92
,:93 ,:94 ,:95 ,:96 ,:97 ,:98 ,:99 ,:100 ,:101 ,:102 ,:103 ,:104 ,:105 ,:106 ,:107 ,:108 ,:109 ,:110 ,:111 ,:112 ,:113 ,:114 ,:115 ,:116 ,:117 ))
利用以下脚本,查看到sql执行情况,确认很慢。
Select inst_id, sql_id, child_number chld, plan_hash_value plan_hash, users_executing exe, executions exes,
parsing_schema_id user_id,
buffer_gets/executions gets,
disk_reads/executions reads,
rows_processed/executions rows_, cpu_time/executions/1000/1000 cpu_ms,
Elapsed_time/executions/1000/1000 elaps_ms,
USER_IO_WAIT_TIME/executions/1000/1000 io_ms,
last_load_time,
to_char(sysdate,'hh24:mi:ss') chk_date
From gv$sql
Where sql_id='dm5fk9c92c7yk'
and executions>0
order by last_load_time
原执行计划如下:
---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | NESTED LOOPS | | 1 | 70 | 2 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 1 | 70 | 2 (0)| 00:00:01 |
|* 3 | TABLE ACCESS BY INDEX ROWID| BOOLEANVALUE | 1 | 28 | 1 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | BOOLEANVALUE$COMPOSITE2 | 1 | | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | PK_WTPARTUSAGELINK | 1 | | 1 (0)| 00:00:01 |
|* 6 | TABLE ACCESS BY INDEX ROWID | WTPARTUSAGELINK | 1 | 42 | 1 (0)| 00:00:01 |
其实这个问题主要是in后面的参数值有100多个,执行计划中并没有走INLIST ITERATOR(迭代)操作,迭代是指in后有多个常量时,只执行一次,而不走迭代时,有多少个常量就要执行多少次。显然,执行计划走迭代性能要好。
手工尝试输入三个参数值代入in中时,发现执行计划有走迭代,而v$sql中只有一个执行计划,无法从cursor中去选择一个好的执行计划来加以固化,询问过开发人员,这是一支由系统自动生成的sql,无法手工去修改SQL,而oracle也没有提供INLIST ITERATOR的hint,手工调整已无法实现,只能依靠oracle本身的优化工具。
通过自动sql tuning和sql profile调整执行计划:
1.针对sql_id建立自动sql tuning任务:
declare
tuning_task_name varchar2(30);
tuning_sqltext clob;
begin
tuning_task_name :=dbms_sqltune.create_tuning_task(
sql_id => 'dm5fk9c92c7yk',
scope =>'COMPREHENSIVE',
time_limit =>2000,
task_name =>'plmsq2',
description=>'Tune T1 count');
end;
2.执行自动sql tuing任务
begin
dbms_sqltune.execute_tuning_task(task_name=>'plmsq2');
end;
3.查询tuing任务完成报告
select dbms_sqltune.report_tuning_task('plmsq2')
from dual
4.比较报告中执行计划好坏,并接受profile:
execute dbms_sqltune.accept_sql_profile(task_name => 'plmsq2', task_owner
=> 'ZENGXUEWEN',force_match=>true,replace => TRUE);
5.查询profile情况
select * from dba_sql_profiles order by created
查得已针对sql建立的profile为SYS_SQLPROF_01560c5445fd0001
调整后的执行计划:
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 47 (100)| |
| 1 | NESTED LOOPS | | 62M| 4147M| 47 (3)| 00:00:01 |
| 2 | NESTED LOOPS | | 62M| 4147M| 47 (3)| 00:00:01 |
| 3 | INLIST ITERATOR | | | | | |
|* 4 | TABLE ACCESS BY INDEX ROWID| BOOLEANVALUE | 96 | 2688 | 18 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | BOOLEANVALUE$COMPOSITE0 | 128 | | 15 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | PK_WTPARTUSAGELINK | 1 | | 1 (0)| 00:00:01 |
|* 7 | TABLE ACCESS BY INDEX ROWID | WTPARTUSAGELINK | 648K| 25M| 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
优化前后性能对比:
调整前(单次执行):
所花时间:5458.77s cpu时间:630.589s 逻辑读:3914415.7 物理读:680683.438
执行计划调整后(单次执行):
所花时间:39.82ms cpu时间:13.86 ms 逻辑读:309 物理读:5.6
调整执行计划后,开发人员反馈变快了。
以下是QQ聊天记录:
SQL如下:
SELECT A0.idA2A2,A0.updateCountA2,A0.classnameA2A2,ABS(NULL),A0.branchIdA2typeDefinitionRefe,A1.idA2A2,A1.updateCountA2,A1.idA3A6,A1.value FROM WTPartUsageLink A0,BooleanValue A1 WHERE (((A1.idA3A6 = :1 ) AND (A1.idA3A4 = A0.idA2A2) AND ((A1.idA3A5 = :2
) OR (A1.idA3A5 IS NULL )))) AND (A0.markForDeleteA2 = 0) AND (A0.idA2A2 IN (:3 ,:4 ,:5 ,:6 ,:7 ,:8 ,:9 ,:10 ,:11 ,:12 ,:13 ,:14 ,:15 ,:16 ,:17 ,:18 ,:19 ,:20 ,:21 ,:22 ,:23 ,:24 ,:25 ,:26 ,:27 ,:28 ,:29 ,:30 ,:31 ,:32 ,:33 ,:34 ,:35 ,:36 ,:37 ,:38 ,:39 ,:40
,:41 ,:42 ,:43 ,:44 ,:45 ,:46 ,:47 ,:48 ,:49 ,:50 ,:51 ,:52 ,:53 ,:54 ,:55 ,:56 ,:57 ,:58 ,:59 ,:60 ,:61 ,:62 ,:63 ,:64 ,:65 ,:66 ,:67 ,:68 ,:69 ,:70 ,:71 ,:72 ,:73 ,:74 ,:75 ,:76 ,:77 ,:78 ,:79 ,:80 ,:81 ,:82 ,:83 ,:84 ,:85 ,:86 ,:87 ,:88 ,:89 ,:90 ,:91 ,:92
,:93 ,:94 ,:95 ,:96 ,:97 ,:98 ,:99 ,:100 ,:101 ,:102 ,:103 ,:104 ,:105 ,:106 ,:107 ,:108 ,:109 ,:110 ,:111 ,:112 ,:113 ,:114 ,:115 ,:116 ,:117 ))
利用以下脚本,查看到sql执行情况,确认很慢。
Select inst_id, sql_id, child_number chld, plan_hash_value plan_hash, users_executing exe, executions exes,
parsing_schema_id user_id,
buffer_gets/executions gets,
disk_reads/executions reads,
rows_processed/executions rows_, cpu_time/executions/1000/1000 cpu_ms,
Elapsed_time/executions/1000/1000 elaps_ms,
USER_IO_WAIT_TIME/executions/1000/1000 io_ms,
last_load_time,
to_char(sysdate,'hh24:mi:ss') chk_date
From gv$sql
Where sql_id='dm5fk9c92c7yk'
and executions>0
order by last_load_time
原执行计划如下:
---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2 (100)| |
| 1 | NESTED LOOPS | | 1 | 70 | 2 (0)| 00:00:01 |
| 2 | NESTED LOOPS | | 1 | 70 | 2 (0)| 00:00:01 |
|* 3 | TABLE ACCESS BY INDEX ROWID| BOOLEANVALUE | 1 | 28 | 1 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | BOOLEANVALUE$COMPOSITE2 | 1 | | 1 (0)| 00:00:01 |
|* 5 | INDEX UNIQUE SCAN | PK_WTPARTUSAGELINK | 1 | | 1 (0)| 00:00:01 |
|* 6 | TABLE ACCESS BY INDEX ROWID | WTPARTUSAGELINK | 1 | 42 | 1 (0)| 00:00:01 |
其实这个问题主要是in后面的参数值有100多个,执行计划中并没有走INLIST ITERATOR(迭代)操作,迭代是指in后有多个常量时,只执行一次,而不走迭代时,有多少个常量就要执行多少次。显然,执行计划走迭代性能要好。
手工尝试输入三个参数值代入in中时,发现执行计划有走迭代,而v$sql中只有一个执行计划,无法从cursor中去选择一个好的执行计划来加以固化,询问过开发人员,这是一支由系统自动生成的sql,无法手工去修改SQL,而oracle也没有提供INLIST ITERATOR的hint,手工调整已无法实现,只能依靠oracle本身的优化工具。
通过自动sql tuning和sql profile调整执行计划:
1.针对sql_id建立自动sql tuning任务:
declare
tuning_task_name varchar2(30);
tuning_sqltext clob;
begin
tuning_task_name :=dbms_sqltune.create_tuning_task(
sql_id => 'dm5fk9c92c7yk',
scope =>'COMPREHENSIVE',
time_limit =>2000,
task_name =>'plmsq2',
description=>'Tune T1 count');
end;
2.执行自动sql tuing任务
begin
dbms_sqltune.execute_tuning_task(task_name=>'plmsq2');
end;
3.查询tuing任务完成报告
select dbms_sqltune.report_tuning_task('plmsq2')
from dual
4.比较报告中执行计划好坏,并接受profile:
execute dbms_sqltune.accept_sql_profile(task_name => 'plmsq2', task_owner
=> 'ZENGXUEWEN',force_match=>true,replace => TRUE);
5.查询profile情况
select * from dba_sql_profiles order by created
查得已针对sql建立的profile为SYS_SQLPROF_01560c5445fd0001
调整后的执行计划:
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 47 (100)| |
| 1 | NESTED LOOPS | | 62M| 4147M| 47 (3)| 00:00:01 |
| 2 | NESTED LOOPS | | 62M| 4147M| 47 (3)| 00:00:01 |
| 3 | INLIST ITERATOR | | | | | |
|* 4 | TABLE ACCESS BY INDEX ROWID| BOOLEANVALUE | 96 | 2688 | 18 (0)| 00:00:01 |
|* 5 | INDEX RANGE SCAN | BOOLEANVALUE$COMPOSITE0 | 128 | | 15 (0)| 00:00:01 |
|* 6 | INDEX UNIQUE SCAN | PK_WTPARTUSAGELINK | 1 | | 1 (0)| 00:00:01 |
|* 7 | TABLE ACCESS BY INDEX ROWID | WTPARTUSAGELINK | 648K| 25M| 1 (0)| 00:00:01 |
----------------------------------------------------------------------------------------------------------
优化前后性能对比:
调整前(单次执行):
所花时间:5458.77s cpu时间:630.589s 逻辑读:3914415.7 物理读:680683.438
执行计划调整后(单次执行):
所花时间:39.82ms cpu时间:13.86 ms 逻辑读:309 物理读:5.6
调整执行计划后,开发人员反馈变快了。
以下是QQ聊天记录:
代言人 15:25:40 调整了 |
代言人 15:25:49 退出系统,重新再试下 |
|
xx 15:25:52 好 |
xx 15:31:07 速度快了 |
相关文章推荐
- Oracle 学习:约束、查询语句
- Oracle系列问题解决
- 整合SSH框架 (Struts2.x+Spring3.x+hibernate3.x+oracle)
- 6.Hibernate 关联关系
- oracle系统结构的认识
- oracle用SQL Plus输入命令为什么只显示2
- Linux下的Oracle 11gr2安装完成的的自启动操作。
- oracle分页
- Oracle 11g 默认用户名和密码不正确
- Oracle/Sun JDK与OpenJDK的区别和联系
- 【泛型】跟着 Oracle java doc 学习 <1> 泛型
- 如何更改Oracle字符集避免乱码
- ORACLE数据库---多表链接查询
- Oracle Fusion Middleware 12c GoldenGate Studio Installation
- Oracle Fusion Middleware 12c GoldenGate Studio Installation
- win10安装oracle 11g 时出现INS-13001环境不满足最低要求
- Oracle数据库基础知识点
- oracle查询排序asc/desc 多列 order by
- Oracle11g数据库win8.1系统安装配置图文教程
- Oracle 学习笔记