暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

烂SQL导致的慢查询排查

原创 DB巡航者 2023-08-03
296

一、问题背景

上个月将生产环境的某个库迁移到新的节点后,经常会在凌晨出现CPU偏高的告警。查看监控图表如图一所示。

图一、问题时间段的数据库资源使用指标曲线

根据告警日志排查,发现源头的数据库实例是一个从库,供业务系统大数据报表使用的,作为大数据ETL的数据源。

进一步,通过性能诊断工具查看,发生问题的时间段发现有密集的慢SQL。

图二、问题时间段的慢SQL

二、问题分析过程

2.1 资源负载和业务流量分析

在图一展示的各条SQL语句中,排名第一的Select语句最大执行时间16s。

首先查看与这条语句相关的资源负载和业务流量情况。如图三所示,在问题事件段,活跃会话数(AAS)最高一度达到了80,远超CPU核数,说明并发也很高,执行期间引起了cpu100%以及网络IO的明显增长(纵向对比同时间段的Utils和Bytes IN/OUT曲线的可以看到)。

图三、SQL关联分析

2.2 慢查询分析

图四、慢查询分析

捕获的样例SQL:

SELECT `layout_id`,... FROM channel_layout_api WHERE layout_id%100 >= 431494 AND layout_id%100 < 433160
  • 如图四所示,选中问题SQL,点击“查询执行计划”,发现查询类型为ALL,即全表扫描,扫描行数接近35w。
  • 查看样例SQL的查询条件,发现有使用%100取模运算。
  • 取模后的条件比较也有问题,100取模后必定<486472,即该条件无过滤效果,结果集也是全表,没达到取模的效果。
  • 查询数据库表结构与索引情况,结果如下,查询字段layout_id为主键索引。
channel_layout_api | CREATE TABLE `channel_layout_api` (
  `layout_id` bigint(20) NOT NULL AUTO_INCREMENT,
  `create_time` bigint(11) NOT NULL DEFAULT '0' COMMENT '创建时间',
  ......省略无关字段
  PRIMARY KEY (`layout_id`),
  .......省略无关索引
) 

三、问题根因定位

原因1:虽然layout_id为主键索引,但是由于查询条件里使用了取模运算,导致索引失效。

原因2:取模操作后的比较条件有问题,导致查询的返回结果不是预期的1/100的数据,而是全表的数据,进一步恶化SQL执行效率。

知识扩展:

(1)该场景索引失效的原因:

Innodb索引采用B+tree模型,按照【索引值】有序排列存储,而不是按照取模计算后的值存储,取模计算后的值无法与索引值进行比较,所以无法走索引,只能通过把索引字段的取值都取出来,然后依次进行表达式的计算来进行条件判断,因此采用的就是全表扫描的方式。

(2)其他常见索引失效场景:

  • 联合索引不遵循最左前缀原则
  • 对索引字段进行函数计算
  • 对索引字段进行运算符计算
  • 对索引字段进行左、左右模糊匹配
  • 对索引进行类型转换,包括隐式转换
  • OR前后存在非索引列
  • 数据倾斜,符合索引条件的数据占比很高

四、优化建议

开发优化建议:

  • 考虑是否必须使用取模操作,能否修改ETL取数规则,比如按照id或者时间范围切分查询。
  • 修复错误的无过滤效果的比较条件。
最后修改时间:2023-08-08 17:24:26
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论