生产环境sql语句调优实战第五篇(r2笔记41天)
今天在生产环境中发现一条sql语句尽管走了主键索引,但是查询还是很慢。
sql语句类似下面的形式:
SELECT /*+ index (bl1_cyc_payer_pop BL1_CYC_PAYER_POP_PK) */
T_TAX.BA_NO,
T_TAX.TOTAL_TAX_AMT,
T_TAX.TAX_RELATION,
T_TAX_ITEM.TAX_ITEM_SEQ_NO,
T_TAX_ITEM.TAX_SEQ_NO,
T_TAX_ITEM.TAX_AUTHORITY,
T_TAX_ITEM.TAX_TYPE,
T_TAX_ITEM.TAX_RATE,
T_TAX_ITEM.TAX_AMOUNT,
T_TAX_ITEM.TAXABLE_AMOUNT,
.......
FROM T_TAX, T_TAX_ITEM, T_DOCUMENT, T_CYC_PAYER_POP --这几张都是大表,少则500万左右,多则1000多万。
WHERE T_TAX.TAX_ITEM_PERIOD_KEY = T_TAX_ITEM.PERIOD_KEY
AND T_TAX.CUSTOMER_KEY = T_CYC_PAYER_POP.CUSTOMER_KEY
AND T_TAX.BA_NO = T_CYC_PAYER_POP.BA_NO
AND T_TAX.CYCLE_SEQ_NO = T_CYC_PAYER_POP.CYCLE_SEQ_NO
AND T_TAX.CYCLE_SEQ_RUN = T_CYC_PAYER_POP.CYCLE_SEQ_RUN
AND T_TAX.PERIOD_KEY = T_CYC_PAYER_POP.PERIOD_KEY
AND T_TAX_ITEM.CUSTOMER_KEY = T_CYC_PAYER_POP.CUSTOMER_KEY
AND T_TAX_ITEM.TAX_SEQ_NO = T_TAX.TAX_SEQ_NO
AND T_DOCUMENT.PERIOD_KEY = T_CYC_PAYER_POP.PERIOD_KEY
AND T_DOCUMENT.CUSTOMER_KEY = T_CYC_PAYER_POP.CUSTOMER_KEY
AND T_DOCUMENT.BA_NO = T_CYC_PAYER_POP.BA_NO
AND T_DOCUMENT.CYCLE_SEQ_NO = T_CYC_PAYER_POP.CYCLE_SEQ_NO
AND T_DOCUMENT.CYCLE_SEQ_RUN = T_CYC_PAYER_POP.CYCLE_SEQ_RUN
AND T_DOCUMENT.DOC_PRODUCE_IND IN ('Y', 'E')
AND T_CYC_PAYER_POP.CUSTOMER_KEY = 78
AND T_CYC_PAYER_POP.PERIOD_KEY = 55
AND T_CYC_PAYER_POP.QA_GROUP = 3
AND T_CYC_PAYER_POP.CYCLE_SEQ_NO = 2925
查看该sql的执行计划
发现有严重的io问题,瓶颈就在于使用的primary key对应的index
Id |
Operation |
Name |
EstimatedRows |
Cost |
Active Period (56s) |
Execs |
Rows |
Memory |
Temp |
IO Requests |
CPU Activity |
Wait Activity |
|||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
. |
0 |
SELECT STATEMENT |
. |
. |
. |
... |
... |
1 |
67 |
. |
. |
. |
. |
||||||||||
... | |||||||||||||||||||||||
. |
1 |
. NESTED LOOPS |
. |
. |
. |
... |
... |
1 |
67 |
. |
. |
. |
. |
||||||||||
... | |||||||||||||||||||||||
. |
2 |
.. NESTED LOOPS |
. |
1 |
2447 |
... |
... |
1 |
67 |
. |
. |
. |
. |
||||||||||
... | |||||||||||||||||||||||
. |
3 |
... NESTED LOOPS |
. |
1 |
2446 |
... |
... |
1 |
67 |
. |
. |
. |
. |
||||||||||
... | |||||||||||||||||||||||
. |
4 |
.... NESTED LOOPS |
. |
1 |
2445 |
... |
... |
1 |
9 |
. |
. |
. |
. |
||||||||||
... | |||||||||||||||||||||||
. |
5 |
.....PARTITION RANGE SINGLE |
. |
1 |
2444 |
... |
... |
1 |
9 |
. |
. |
. |
. |
||||||||||
... | |||||||||||||||||||||||
. |
6 |
...... TABLE ACCESS BY LOCAL INDEX ROWID |
CYC_PAYER_POP |
1 |
2444 |
... |
... |
1 |
9 |
. |
. |
11 (<0.1%) |
11 (<0.1%) |
. |
. |
||||||||
... | |||||||||||||||||||||||
11 (<0.1%) | |||||||||||||||||||||||
-> |
7 |
.......INDEX FULL SCAN |
CYC_PAYER_POP_PK |
1 |
2444 |
.. |
.. |
1 |
793 |
. |
. |
.23172 (95%) |
. |
. |
23172 (95%) |
.100% |
. |
. |
100% |
.100% |
. |
. |
100% |
.. | |||||||||||||||||||||||
. |
. |
23172 (95%) |
|||||||||||||||||||||
. | |||||||||||||||||||||||
. |
. |
100% |
|||||||||||||||||||||
. | |||||||||||||||||||||||
. |
. |
100% |
|||||||||||||||||||||
. |
这个问题很值得深究,完全可以使用如下的方式来验证。我尝试使用pk的Hint,另外不加任何hint,看表查询的时候会不会使用index
-->使用hint强制走主键查询
Plan hash value: 3105767292
---------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
---------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 12 | 2501 (1)| 00:00:31 | | |
| 1 | PARTITION RANGE SINGLE | | 1 | 12 | 2501 (1)| 00:00:31 | 171 | 171 |
|* 2 | TABLE ACCESS BY LOCAL INDEX ROWID| T_CYC_PAYER_POP | 1 | 12 | 2501 (1)| 00:00:31 | 171 | 171 |
|* 3 | INDEX FULL SCAN | T_CYC_PAYER_POP_PK | 541 | | 2444 (1)| 00:00:30 | 171 | 171 |
---------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("T_CYC_PAYER_POP"."QA_GROUP"=3)
3 - access("T_CYC_PAYER_POP"."CYCLE_SEQ_NO"=2925 AND "T_CYC_PAYER_POP"."PERIOD_KEY"=55 AND
"T_CYC_PAYER_POP"."CUSTOMER_KEY"=78)
filter("T_CYC_PAYER_POP"."CUSTOMER_KEY"=78 AND "T_CYC_PAYER_POP"."CYCLE_SEQ_NO"=2925 AND
"T_CYC_PAYER_POP"."PERIOD_KEY"=55)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
31395 consistent gets
0 physical reads
0 redo size
910 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
8 rows processed
-->来看看不使用hint之后,发生了什么
select T_CYC_PAYER_POP.CUSTOMER_KEY,
T_CYC_PAYER_POP.PERIOD_KEY,
T_CYC_PAYER_POP.QA_GROUP ,
T_CYC_PAYER_POP.CYCLE_SEQ_NO
from T_CYC_PAYER_POP where T_CYC_PAYER_POP.CUSTOMER_KEY = 78
AND T_CYC_PAYER_POP.PERIOD_KEY = 55
AND T_CYC_PAYER_POP.QA_GROUP = 3
AND T_CYC_PAYER_POP.CYCLE_SEQ_NO = 2925
/
Execution Plan
----------------------------------------------------------
Plan hash value: 23637115
----------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time | Pstart| Pstop |
----------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 12 | 2 (0)| 00:00:01 | | |
| 1 | PARTITION RANGE SINGLE | | 1 | 12 | 2 (0)| 00:00:01 | 171 | 171 |
|* 2 | TABLE ACCESS BY LOCAL INDEX ROWID| T_CYC_PAYER_POP | 1 | 12 | 2 (0)| 00:00:01 | 171 | 171 |
|* 3 | INDEX RANGE SCAN | T_CYC_PAYER_POP_5IX | 535 | | 1 (0)| 00:00:01 | 171 | 171 |
----------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("T_CYC_PAYER_POP"."CUSTOMER_KEY"=78 AND "T_CYC_PAYER_POP"."PERIOD_KEY"=55)
3 - access("T_CYC_PAYER_POP"."QA_GROUP"=3 AND "T_CYC_PAYER_POP"."CYCLE_SEQ_NO"=2925)
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
951 consistent gets
644 physical reads
80 redo size
910 bytes sent via SQL*Net to client
520 bytes received via SQL*Net from client
2 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
8 rows processed
启用了index range scan,而且从执行计划和统计信息来看,明显要比全索引扫描效率高得多。
可以看到使用index range scan之后,先查询了索引列的信息,然后无法走索引过滤了其他的条件。根据目前的数据情况,这个效率要比全索引效率还高的多。
以下是做了hint的改动之后,统计信息的情况,可以看到明显的改善。对于这个Hint的细节需要和客户做更多的确认,毕竟对于调优不能越调越差,稳定和高效才是关键。
Statistics
----------------------------------------------------------
1 recursive calls
0 db block gets
1178 consistent gets
756 physical reads
0 redo size
3229 bytes sent via SQL*Net to client
553 bytes received via SQL*Net from client
5 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
58 rows processed
- 再议-Golang语言MessageBox用法实例
- linux下通过go语言获得系统进程cpu使用情况的方法
- Golang语言版ssh口令破解工具 --必须亲自敲代码,否则看了白看
- MySQL中insert语句没有响应的问题分析(r11笔记第21天)
- MySQL级联复制中的数据同步(第二篇)(r11笔记第21天)
- Golang语言 - 以任意类型的slices作为输入参数
- HDUOJ-------The Hardest Problem Ever
- Golang语言--【社区推荐阅读】 fmt用法
- 一个SQL性能问题的优化探索(一)(r11笔记第33天)
- HDUOJ-----1074 Integer Inquiry
- PXE无人值守安装Linux
- HDUOJ-----Robot Motion
- 对康托展开的一些心得...
- MySQL 5.7 General Tablespace学习(r11笔记第34天)
- 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 数组属性和方法
- (实战)Node.js 实现抢票小工具&短信通知提醒
- 目标检测 | Anchor free之CenterNet深度解析
- C++第二章 变量与基本类型
- springboot2结合mybatis拦截器实现主键自动生成
- 学习一下Python3的协程
- Android网络收集和ping封装库
- Kubernetes之helm部署使用
- 想掌握 Binder 机制?驱动核心源码详解和Binder超系统学习资源,想学不会都难!
- leetcode链表之回文链表
- Docsify 安装
- Docsify 初始化文件夹
- ELK 日志系统集成 Skywalking 调用链 ID
- ChartCenter ——为您的K8s之旅保驾护航v
- leetcode链表之删除链表的节点
- iOS打包的那一些事情