使用hint来调优sql语句(72天)
最近生产发现有一个sql语句运行耗时达5000多秒。 抓出来sql_id一看,sql倒不是一个很长的语句。结构也很简单。如下。
select company_code, sap_company_id
from data_company_code
where company_code not in
(SELECT distinct l9_company_code
FROM detailed_data_info_v a, refund_request b
WHERE a.financial_activity = 'RFND'
and a.refund_method = 'AP'
AND a.refund_id = b.refund_id
AND b.refund_status = 'P'
AND b. REVERSAL_TRANS_ID is null
AND posting_date = TO_DATE(20140511, 'YYYYMMDD'))
执行计划如下:
Execution Plan
-----------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
-----------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | | | 2696K(100)| | | |
| 1 | FILTER | | | | | | | |
| 2 | MAT_VIEW ACCESS FULL | DATA_COMPANY_CODE | 5 | 35 | 3 (0)| 00:00:01 | | |
| 3 | NESTED LOOPS | | | | | | | |
| 4 | NESTED LOOPS | | 1 | 68 | 1078K (2)| 03:35:43 | | |
| 5 | PARTITION RANGE ALL | | 1 | 59 | 1078K (2)| 03:35:43 | 1 | 366 |
| 6 | TABLE ACCESS FULL | DETAILED_DATA | 1 | 59 | 1078K (2)| 03:35:43 | 1 | 366 |
| 7 | INDEX UNIQUE SCAN | REFUND_REQUEST_PK | 1 | | 1 (0)| 00:00:01 | | |
| 8 | TABLE ACCESS BY INDEX ROWID| REFUND_REQUEST | 1 | 9 | 1 (0)| 00:00:01 | | |
-----------------------------------------------------------------------------------------------------------------------
查看最后的输出表data_company_code,发现是一个数据字典表,里面的数据很少。只有5条。 表 detailed_data_info_v是一个视图,里面参照的基表只有1个. detailed_data_info 它是一个历史表,里面有3亿多条数据。而且对应的主键在查询条件中也没有,这也是这个sql执行慢的主要原因。 表 REFUND_REQUEST 是一个应用表,里面的数据就几百条。 明白了大概的情况之后。 首先从视图下手。看看 a.refund_method , a.refund_id,company_code都运用了大量的decode,可以看到都是基于financial_activity来做的过滤,所以直接可以提出其他的条件过滤,直接使用基表来去得所需的条件。
DECODE( FINANCIAL_ACTIVITY,
'RFND',
DATA_FIELD_1) as REFUND_ID
DECODE( FINANCIAL_ACTIVITY,
'RFND',
DATA_FIELD_3) as REFUND_METHOD
DECODE( FINANCIAL_ACTIVITY,
'RFND',
DATA_FIELD_10 ,
'WERRE',
DATA_FIELD_10 ,
。。。。。。。
DATA_FIELD_19 ,
'BCK',
DATA_FIELD_20 ,
'DSPCAN',
DATA_FIELD_7 ,
'DSPREJ',
DATA_FIELD_7 ,
'WER',
DATA_FIELD_7 ,
'WWER',
DATA_FIELD_7 ,
'DD',
DATA_FIELD_7 ,
'reer',
DATA_FIELD_7 ,
'tttt',
DATA_FIELD_8 ,
'xxxx',
DATA_FIELD_9) as COMPANY_CODE
所以把查询可以构造成几个子查询。黄色是做了变化的部分。
select a.DATA_FIELD_10 l9_company_code
from DETAILED_DATA a
where a.financial_activity = 'RFND'
and a.DATA_FIELD_3 = 'AP'
and a.posting_date = TO_DATE(20140511, 'YYYYMMDD')
另外一个子查询。
select refund_id
from ar1_refund_request b
where b.refund_status='P'
and b.reversal_trans_id is null
/
no rows selected
结果已查询,让我大跌眼镜,竟然没有匹配的值。但是sql语句还是会不断的去做无用功。查了半天,结果返回了一个Null。 找到了基本的方向,如果查询条件中没有匹配的值,至少可以不用再从3亿多条记录的表里去全表扫描了。 在测试下面的查询时,如果屏蔽掉条件a.financial_activity = 'RFND',查询就会直接先进入refund_request了。
SQL> select
distinct a.DATA_FIELD_10 l9_company_code
from DETAILED_DATA a
where a.DATA_FIELD_3 = 'AP'
--and a.financial_activity = 'RFND'
and a.posting_date = TO_DATE(20140512, 'YYYYMMDD')
and exists (select 1
from refund_request b
where b.refund_id = a.DATA_FIELD_1
and b.refund_status = 'P'
and b.reversal_trans_id is null)
/
no rows selected
Elapsed: 00:00:00.01
如果没有数据,马上就返回了。类似于这样的方式
select xxx from huge_table where 1!=1
但是已加入条件financial_activity就开始扫描大表,看来只能使用Hint来强制指定表的访问顺序了。当然了使用hint也是玩不得以而为之。不建议一开始调就考虑hint.
SQL> select company_code, sap_company_id
from ar9_company_code
where company_code not in
(select /*+leading(b,a)*/
distinct a.DATA_FIELD_10 l9_company_code --,financial_activity,DATA_FIELD_3,posting_date
from AR1_GL_DETAILED_DATA a
where a.DATA_FIELD_3 = 'AP'
and a.financial_activity = 'RFND'
and a.posting_date = TO_DATE(20140512, 'YYYYMMDD')
and exists (select 1
from ar1_refund_request b
where b.refund_id = a.DATA_FIELD_1
and b.refund_status = 'P'
and b.reversal_trans_id is null))
SQL> /
COMPAN SAP_COMPANY_ID
------ --------------
AE 1010
XX 1068
XXE 1067
DS 1027
EER 1019
Elapsed: 00:00:00.01
- linux下的缓存机制及清理buffer/cache/swap的方法梳理
- 分组合计且排序和显示名称
- silverlight动态读取txt文件/解析json数据/调用wcf示例
- Junit加载Spring容器作单元测试_添加事务回滚
- 实现三遍决策树,你就会想出更快的算法!
- 将一段复杂文本变成字符串的赋值语句
- Linux下squid代理缓存服务环境部署
- linux下清除Squid缓存的方法记录
- memcached缓存知识简单梳理
- Idea 常用快捷键
- silverlight中如何方便在多个"场景"即Xaml文件之间随意切换?
- 电子签名实现的思路、困难及解决方案
- JavaScript排序算法详解
- 事件处理需小心
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 算法集锦(3)|采用医疗数据预测糖尿病的算法
- 谁说Cat不能做链路跟踪的,给我站出来
- Libra:一种Python工具,可以用几行代码自动实现机器学习过程
- 国内首个“新基建”安全大赛启动了!
- Kubernetes 中 Informer 的使用
- 嵌入式开发中常见3个的C语言技巧
- 恕我直言,我也是才知道ElasticSearch条件更新是这么玩的
- 有了MinIO,你还会用FastDFS么?
- STP 实验
- 算法集锦(6) |基于GPU框架的tensorflow数据增强算法
- 交换机端口安全实验
- 算法集锦(7)| 实用代码 | Google Colab使用及配置技巧
- 浏览器标签页分屏_不同浏览器同一个tab里面怎么实现分屏?#技能get#
- 微信小程序开发实战(16):交互组件
- Linux常用命令