2018年4月20日,移动某平台江苏某业务系统发起SQL调优请求,在本次MySQL调试过程中遇到了exists关联子查询导致的sql
性能及其低下,并且相关的SQL语句执行速度及其不稳定忽快忽慢;通过重写相关SQL的exists部分修改成等值子查询,相关sql的
性能得到极大提高,并且执行速度比较稳定。本次SQL优化过程记录如下:
1、环境信息:
操作系统版本:CENTOS 7.2.1151
数据库版本:5.7.17-log
2、查看MySQL慢日志相关信息
ysql>show variables like '%slow_query_%';
-+-------------------------------------------+--------------------------------------------------------------------------------+
| Variable_name | Value |
-+-------------------------------------------+--------------------------------------------------------------------------------+
|slow_query_log | ON |
|slow_query_log_file |/data/mysql/db/elog/slow.log |
-+-------------------------------------------+--------------------------------------------------------------------------------+
2、使用pt工具分析MySQL的慢日志
cd /data/mysql/db/elog
pt-query-digest slow.log --since '2018-04-13 00:00:00' --until '2018-04-19 00:00:00' >>slow_report_log
--第二条要优化的SQL对象
0x56B6B418ADAAB135
--SQL执行计划
-- SQL执行统计信息概要
5、首先看第一条SQL语句,自己的优化思路,确定SQL语句中慢的具体位置
--对第一条SQL语句拆分,以union为界分两部分
-- 0xEA33702BDD78E0BA第一部分:0xEA33702BDD78E0BA_part1
0xEA33702BDD78E0BA_part1部分SQL语句查询只有13条记录,执行速度非常快0.00秒完成
-- 0xEA33702BDD78E0BA第二部分:0xEA33702BDD78E0BA_part2
0xEA33702BDD78E0BA_part2部分SQL(该部分查询正常出结果是103条数据)语句执行超过10s,超时退出
6、接下来着重关注 0xEA33702BDD78E0BA第二部分:0xEA33702BDD78E0BA_part2
观察SQL语句发现有EXISTS关联子查询,我的理解是,原先sql被优化器改写,主查询执行多次,每次主查询sql都不同,
都会发起物理读盘扫表。于是考虑将其改为等值连接子查询:
-- SQL改写后(查询结果集与修改前一致): 两个等值查询表结果集在内存,接下来是最终 结果集匹配和过滤,执行速度只有0.01秒
7、修改后的完整SQL如下
--修改后的sql执行速度,有原先的超过10s超时中断退出降低到0.00秒以下。
--SQL改写后的执行计划
8、第二条SQL语句采用第一条SQL语句优化方法,将exists关联子查询改写为表关联的等值子查询
--改写前的执行效率
--改写后的执行效率
--改写后的SQL执行计划
9、总结
通过观察SQL改写前后的执行计划,可以发现改写后的SQL 执行中间结果集均已缓存到内存(Using join buffer(Block Nested Loop)),内存结果集匹配过滤降低了表的物理IO,从而提高了SQL的执行性能。
性能及其低下,并且相关的SQL语句执行速度及其不稳定忽快忽慢;通过重写相关SQL的exists部分修改成等值子查询,相关sql的
性能得到极大提高,并且执行速度比较稳定。本次SQL优化过程记录如下:
1、环境信息:
操作系统版本:CENTOS 7.2.1151
数据库版本:5.7.17-log
2、查看MySQL慢日志相关信息
ysql>show variables like '%slow_query_%';
-+-------------------------------------------+--------------------------------------------------------------------------------+
| Variable_name | Value |
-+-------------------------------------------+--------------------------------------------------------------------------------+
|slow_query_log | ON |
|slow_query_log_file |/data/mysql/db/elog/slow.log |
-+-------------------------------------------+--------------------------------------------------------------------------------+
2、使用pt工具分析MySQL的慢日志
cd /data/mysql/db/elog
pt-query-digest slow.log --since '2018-04-13 00:00:00' --until '2018-04-19 00:00:00' >>slow_report_log
3、查看慢日志分析报告
slow_report_log
通过慢日志分析报告发现两条运行缓慢的SQL语句Query_ID分别是0xEA33702BDD78E0BA、0x56B6B418ADAAB135,其中
0xEA33702BDD78E0BA的响应时间占据了整个数据库时间的97.1%,是重点优化对象。
4、明确需要优化的对象
--第一条需要优化的重点对象 0xEA33702BDD78E0BA
--SQL执行计划
-- SQL执行统计信息概要
通过慢日志分析报告发现两条运行缓慢的SQL语句Query_ID分别是0xEA33702BDD78E0BA、0x56B6B418ADAAB135,其中
0xEA33702BDD78E0BA的响应时间占据了整个数据库时间的97.1%,是重点优化对象。
4、明确需要优化的对象
--第一条需要优化的重点对象 0xEA33702BDD78E0BA
--SQL执行计划
-- SQL执行统计信息概要
--第二条要优化的SQL对象
0x56B6B418ADAAB135
--SQL执行计划
-- SQL执行统计信息概要
5、首先看第一条SQL语句,自己的优化思路,确定SQL语句中慢的具体位置
--对第一条SQL语句拆分,以union为界分两部分
-- 0xEA33702BDD78E0BA第一部分:0xEA33702BDD78E0BA_part1
0xEA33702BDD78E0BA_part1部分SQL语句查询只有13条记录,执行速度非常快0.00秒完成
-- 0xEA33702BDD78E0BA第二部分:0xEA33702BDD78E0BA_part2
0xEA33702BDD78E0BA_part2部分SQL(该部分查询正常出结果是103条数据)语句执行超过10s,超时退出
6、接下来着重关注 0xEA33702BDD78E0BA第二部分:0xEA33702BDD78E0BA_part2
观察SQL语句发现有EXISTS关联子查询,我的理解是,原先sql被优化器改写,主查询执行多次,每次主查询sql都不同,
都会发起物理读盘扫表。于是考虑将其改为等值连接子查询:
-- SQL改写后(查询结果集与修改前一致): 两个等值查询表结果集在内存,接下来是最终 结果集匹配和过滤,执行速度只有0.01秒
7、修改后的完整SQL如下
--修改后的sql执行速度,有原先的超过10s超时中断退出降低到0.00秒以下。
--SQL改写后的执行计划
8、第二条SQL语句采用第一条SQL语句优化方法,将exists关联子查询改写为表关联的等值子查询
--改写前的执行效率
--改写后的执行效率
--改写后的SQL执行计划
9、总结
通过观察SQL改写前后的执行计划,可以发现改写后的SQL 执行中间结果集均已缓存到内存(Using join buffer(Block Nested Loop)),内存结果集匹配过滤降低了表的物理IO,从而提高了SQL的执行性能。