实战演练(二):运行20小时的报表SQL优化后秒出

简介:

一、概述

这是我们SQL优化班的一个学员,据说该SQL在生产环境中已经运行了20个小时,快把服务器的磁盘资源耗尽了。这20个小时,我们可爱的学员就是靠着删除一些不重要的文件才能够勉强度过。
据了解,该SQL为一个月运行一次的跑报表的SQL,主要问题是随着SQL的运行时间越来越长,所需的临时表空间也越来越大,导致磁盘资源用尽。

二、先看慢SQL

 ●  SQL 执行时长 ,目前已经20小时,还在继续执行
 
  1. SELECT

  2. COUNT( * ) AS totalNum,

  3. sum( CASE WHEN F.ALARM_LEVEL = 1 THEN 1 ELSE 0 END ) AS LEVELS1,

  4. sum( CASE WHEN F.ALARM_LEVEL = 2 THEN 1 ELSE 0 END ) AS LEVELS2,

  5. sum( CASE WHEN F.ALARM_LEVEL = 3 THEN 1 ELSE 0 END ) AS LEVELS3,

  6. sum( CASE WHEN F.DEAL_STATE = 0 THEN 1 ELSE 0 END ) AS DESTS

  7. FROM

  8. F

  9. LEFT JOIN DC ON DC.ID = F.CONST_ID

  10. LEFT JOIN V ON V.ID = F.VEHICLE_ID

  11. LEFT JOIN AREA ON AREA.ID = V.SYS_DIVISION_ID

  12. WHERE

  13. DC.ID IS NOT NULL

  14. AND V.ID IS NOT NULL

  15. AND F.DEAL_STATE = 0

  16. AND ALARM_LEVEL IN ( 1, 2, 3 )

  17. AND F.VEHICLE_ID IN (

  18. SELECT

  19. VEHICLE_ID

  20. FROM

  21. GVLK

  22. WHERE

  23. GROUP_ID IN ( SELECT GROUP_ID FROM GULK WHERE USER_ID = 'ff8080816091b09c0161f9b825750a9a' )

  24. UNION

  25. SELECT

  26. VEHICLE_ID

  27. FROM

  28. UVLK

  29. WHERE

  30. USER_ID = 'ff8080816091b09c0161f9b825750a9a'

  31. )

  32. AND date( F.ALARM_TIME ) BETWEEN '2000-01-01'

  33. AND '2018-08-14'

  34. AND AREA.PATH LIKE CONCAT( ( SELECT ARE.PATH FROM ARE WHERE ARE.ID = '0' ), '%' )

上述SQL的含义:将F左连DC ,V,AREA表的结果进行where过滤,where中存在子查询,并且还有like函数

 ●  查看执行计划 

0e35d7be5dd1e41bc8d5cddb82a30498dfa0ac31
该执行计划如何看:

id=1的列开始,可以看出 F表,DC表,V表,AREA表都属于id=1的,原因是他们使用了left join,都属于同一个层级。

id=2的部分,分成两块,先看靠前的那块, select type 是DEPENDENT SUBQUERY,看table部分是 是一个子查询,注意subquery3,所以具体的子查询是id=3的部分。 靠后的部分是一个简单的SQL。

id=3的部分,select type是MATERIALIZED ,table 是 UVLK,发生物化视图的是子查询部分中的子查询部分,物化子查询,一般出现物化视图说明子查询中存在嵌套子查询,且是与SQL主体部分完全无关的表,且子查询中并未使用到索引。

id=4部分,是一个DEPENDENT UNION ,将id=2的DEPENDENT SUBQUERY进行union

null部分,union result,是将union的结果集,使用了 using tempory。

id=5部分,是一个子查询,是concat函数的主体部分

 ●  问题定位

执行计划中可以看出,GVLK, GULK, UVLK 部分均使用了DEPEND SUBQUERY,是性能的瓶颈,DEPEND SUBQUERY是依赖于SQL的主体部分,它的执行次数最大可能和SQL主体部分结果的行数(448612行)一样多,同时,,GVLK, GULK,UVLK几张表的type都为all,并为使用到索引,MySQL中关联未走索引的表,只有nested loop join(将驱动表/外部表的结果集作为循环基础数据,然后循环从该结果集每次一条获取数据作为下一个表的过滤条件查询数据,然后合并结果。),多表 join的结果就是,临时结果集会非常非常的大。

三、SQL优化过程

 ●  验证驱动表F的条件过滤性
 
 
  1. SELECT

  2. COUNT( * ) AS totalNum

  3. FROM

  4. F

  5. WHERE F.DEAL_STATE = 0

  6. AND ALARM_LEVEL IN ( 1, 2, 3 )

  7. AND F.ALARM_TIME BETWEEN '2000-01-01' AND '2018-08-14'

上面的sql 运行10s 结果集为393653条数据,说明where 条件中的过滤条件的选择率不是很好 不适合创建索引。

 ●  验证子查询的过滤性
 
 
  1. SELECT

  2. VEHICLE_ID

  3. FROM

  4. GVLK

  5. WHERE GROUP_ID IN ( SELECT GROUP_ID FROM GULK WHERE USER_ID = 'ff8080816091b09c0161f9b825750a9a' )

  6. UNION

  7. SELECT

  8. VEHICLE_ID

  9. FROM

  10. UVLK

  11. WHERE USER_ID = 'ff8080816091b09c0161f9b825750a9a'

上面的SQL 运行了0.5s 结果为1200条 。in里的结果速度快 结果集很小 ,F表 就该结果进行in操作,也会有大幅度的过滤。

 ●  DEPEND SUBQUERY 改写
 
 
  1. SELECT

  2. COUNT( * ) AS totalNum

  3. FROM

  4. F

  5. join (

  6. SELECT

  7. VEHICLE_ID

  8. FROM

  9. GVLK

  10. WHERE

  11. GROUP_ID IN ( SELECT GROUP_ID FROM GULK WHERE USER_ID = 'ff8080816091b09c0161f9b825750a9a' )

  12. UNION

  13. SELECT

  14. VEHICLE_ID

  15. FROM

  16. UVLK

  17. WHERE

  18. USER_ID = 'ff8080816091b09c0161f9b825750a9a'

  19. ) s

  20. WHERE F.DEAL_STATE = 0

  21. AND ALARM_LEVEL IN ( 1, 2, 3 )

  22. AND F.VEHICLE_ID = s.VEHICLE_ID

  23. AND F.ALARM_TIME BETWEEN '2000-01-01' AND '2018-08-14'

最后运行了如下sql 结果集为 88696 速度为0.5s。采用join的方式替代in的方式,因为 DEPEND SUBQUERY是依赖于SQL的主体部分,执行的次数与被依赖表结果集一致。

四、SQL优化结果

 
 
  1. explain extended

  2. SELECT

  3. COUNT( * ) AS totalNum,

  4. sum( CASE WHEN F.ALARM_LEVEL = 1 THEN 1 ELSE 0 END ) AS LEVELS1,

  5. sum( CASE WHEN F.ALARM_LEVEL = 2 THEN 1 ELSE 0 END ) AS LEVELS2,

  6. sum( CASE WHEN F.ALARM_LEVEL = 3 THEN 1 ELSE 0 END ) AS LEVELS3,

  7. sum( CASE WHEN F.DEAL_STATE = 0 THEN 1 ELSE 0 END ) AS DESTS

  8. FROM

  9. F

  10. straight_join (

  11. SELECT

  12. VEHICLE_ID

  13. FROM

  14. GVLK

  15. WHERE

  16. GROUP_ID IN ( SELECT GROUP_ID FROM GULK WHERE USER_ID = 'ff8080816091b09c0161f9b825750a9a' )

  17. UNION

  18. SELECT

  19. VEHICLE_ID

  20. FROM

  21. UVLK

  22. WHERE

  23. USER_ID = 'ff8080816091b09c0161f9b825750a9a'

  24. ) s on F.VEHICLE_ID = s.VEHICLE_ID

  25. straight_join DC ON DC.ID = F.CONST_ID

  26. straight_join V ON V.ID = F.VEHICLE_ID

  27. straight_join AREA ON AREA.ID = V.SYS_DIVISION_ID

  28. WHERE

  29. DC.ID IS NOT NULL

  30. AND V.ID IS NOT NULL

  31. AND F.DEAL_STATE = 0

  32. AND ALARM_LEVEL IN ( 1, 2, 3 )

  33. AND date( F.ALARM_TIME ) BETWEEN '2000-01-01'

  34. AND '2018-08-14'

  35. AND AREA.PATH LIKE CONCAT( ( SELECT ARE.PATH FROM ARE WHERE ARE.ID = '0' ), '%' )

11efc62c5f79d133c67ac885b6436279f9e67620

优化后的SQL的执行时间几乎是秒出。

优化的原理已经在优化过程中详细讲解,速度提升上万倍,原因如下:

1、使用join 代替in的方式;

2、修改后的语句可以使用到索引,索引为F.const_id,table为。这里值得一提的是,采用straight_join 代替 了 join,保证了SQL执行顺序一定是按照我们SQL书写的顺序。

四、后记

本文主要在于优化DEPEND SUBQUERY,另外让SQL能够用得上索引,让SQL的速度有着显著的提升。

希望给大家漫漫的SQL优化之旅,带来不一样的火花。
感谢大家细心观看,如果大家要学习SQL优化,可以来「知数堂」跟着SQL优化班授课老师-松华老师,你知道的,不知道的,他都能教你。


原文发布时间为:2018-10-31
本文作者:郑松华老师&小鹿
本文来自云栖社区合作伙伴“ 老叶茶馆”,了解相关信息可以关注“ 老叶茶馆”。
相关文章
|
6月前
|
SQL 存储 监控
SQL日志优化策略:提升数据库日志记录效率
通过以上方法结合起来运行调整方案, 可以显著地提升SQL环境下面向各种搜索引擎服务平台所需要满足标准条件下之数据库登记作业流程综合表现; 同时还能确保系统稳健运行并满越用户体验预期目标.
351 6
|
SQL 运维 监控
SQL查询太慢?实战讲解YashanDB SQL调优思路
本文是Meetup第十期“调优实战专场”的第二篇技术文章,上一篇《高效查询秘诀,解码YashanDB优化器分组查询优化手段》中,我们揭秘了YashanDB分组查询优化秘诀,本文将通过一个案例,助你快速上手YashanDB慢日志功能,精准定位“慢SQL”后进行优化。
|
SQL 关系型数据库 MySQL
MySQL进阶突击系列(07) 她气鼓鼓递来一条SQL | 怎么看执行计划、SQL怎么优化?
在日常研发工作当中,系统性能优化,从大的方面来看主要涉及基础平台优化、业务系统性能优化、数据库优化。面对数据库优化,除了DBA在集群性能、服务器调优需要投入精力,我们研发需要负责业务SQL执行优化。当业务数据量达到一定规模后,SQL执行效率可能就会出现瓶颈,影响系统业务响应。掌握如何判断SQL执行慢、以及如何分析SQL执行计划、优化SQL的技能,在工作中解决SQL性能问题显得非常关键。
|
8月前
|
前端开发 JavaScript Java
基于springboot+vue开发的校园食堂评价系统【源码+sql+可运行】【50809】
本系统基于SpringBoot与Vue3开发,实现校园食堂评价功能。前台支持用户注册登录、食堂浏览、菜品查看及评价发布;后台提供食堂、菜品与评价管理模块,支持权限控制与数据维护。技术栈涵盖SpringBoot、MyBatisPlus、Vue3、ElementUI等,适配响应式布局,提供完整源码与数据库脚本,可直接运行部署。
474 6
基于springboot+vue开发的校园食堂评价系统【源码+sql+可运行】【50809】
|
11月前
|
SQL 存储 自然语言处理
SQL的解析和优化的原理:一条sql 执行过程是什么?
SQL的解析和优化的原理:一条sql 执行过程是什么?
SQL的解析和优化的原理:一条sql 执行过程是什么?
|
SQL 关系型数据库 MySQL
如何优化SQL查询以提高数据库性能?
这篇文章以生动的比喻介绍了优化SQL查询的重要性及方法。它首先将未优化的SQL查询比作在自助餐厅贪多嚼不烂的行为,强调了只获取必要数据的必要性。接着,文章详细讲解了四种优化策略:**精简选择**(避免使用`SELECT *`)、**专业筛选**(利用`WHERE`缩小范围)、**高效联接**(索引和限制数据量)以及**使用索引**(加速搜索)。此外,还探讨了如何避免N+1查询问题、使用分页限制结果、理解执行计划以及定期维护数据库健康。通过这些技巧,可以显著提升数据库性能,让查询更高效流畅。
|
SQL 关系型数据库 MySQL
基于SQL Server / MySQL进行百万条数据过滤优化方案
对百万级别数据进行高效过滤查询,需要综合使用索引、查询优化、表分区、统计信息和视图等技术手段。通过合理的数据库设计和查询优化,可以显著提升查询性能,确保系统的高效稳定运行。
788 9
|
SQL Oracle 关系型数据库
如何在 Oracle 中配置和使用 SQL Profiles 来优化查询性能?
在 Oracle 数据库中,SQL Profiles 是优化查询性能的工具,通过提供额外统计信息帮助生成更有效的执行计划。配置和使用步骤包括:1. 启用自动 SQL 调优;2. 手动创建 SQL Profile,涉及收集、执行调优任务、查看报告及应用建议;3. 验证效果;4. 使用 `DBA_SQL_PROFILES` 视图管理 Profile。
|
关系型数据库 MySQL 网络安全
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
5-10Can't connect to MySQL server on 'sh-cynosl-grp-fcs50xoa.sql.tencentcdb.com' (110)")
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
799 13
下一篇
开通oss服务