一句慢 SQL 执行 600 秒?!你咋不上天呢

当前文章收录状态:
查询中...

最近看了眼我们数据库的监控,属实被吓到了,竟然有这么多慢 SQL!

图片[1]-一句慢 SQL 执行 600 秒?!你咋不上天呢-明恒博客

其中,有一条慢 SQL 更是逆天,执行了 600 多秒?!

图片[2]-一句慢 SQL 执行 600 秒?!你咋不上天呢-明恒博客

看到这,我当时就是这表情:

图片[3]-一句慢 SQL 执行 600 秒?!你咋不上天呢-明恒博客

如果不是我有看监控的意识,估计这种慢 SQL 还在持续拖慢我们的数据库和项目,我团队的后端朋友们还需要锻炼锻炼呀!

借这个机会,给大家分享一点儿慢 SQL 优化的知识。

什么是慢 SQL?

先解释一下,慢 SQL 指的是执行时间较长的 SQL 查询或操作。它不是一个固定的时间定义,而是根据具体的应用场景和性能要求来决定。

比如你要从几万条数据中查出某一条数据,超过几百毫秒就已经算是慢 SQL 了;但如果你要向数据库插入几万条数据,可能几十秒都不算是慢 SQL。慢是相对的,没有固定的标准。

某种情况下,也可以将消耗数据库资源过多的 SQL 归纳为慢 SQL,因为它们的危害是一样的:都会增加数据的负载、降低数据库的响应速度,有些慢 SQL 还可能导致数据库的锁被占用,从而影响到整个数据库的性能。

所以一般情况下,我们要定期检查数据库中的慢 SQL。

如何检测分析慢 SQL?

“如何检测分析慢 SQL” 也是一道经典的面试题了,对于 MySQL 来说,可以分析 MySQL 自带的慢查询日志、通过 Explain 查看 SQL 的执行计划、通过 Profiling 分析 MySQL 查询的详细执行信息等。

不过俗话说得好,面试造火箭,工作拧螺丝。

一般有些规模的公司都会有自己的慢 SQL 收集分析平台,哪还需要自己敲命令呢?像我们鱼厂虽然是小公司,也可以用大公司提供的云服务呀!慢日志监控、告警、甚至是优化建议,都帮忙做好了,直接使用美滋滋~

图片[4]-一句慢 SQL 执行 600 秒?!你咋不上天呢-明恒博客

如何优化慢 SQL?

下面就以这句最大执行了 600 多秒的坑爹小 SQL 为例,简单聊一下怎么优化。

图片[5]-一句慢 SQL 执行 600 秒?!你咋不上天呢-明恒博客

这条 SQL 的作用是查询指定权限的用户在某段时间内发送的消息记录。由于消息记录表(message_record)和用户表(user)的数据量都非常大,再加上有关联查询,导致查询缓慢。

如图,执行 600 多秒的 SQL 扫描了 600 多万行数据:

图片[6]-一句慢 SQL 执行 600 秒?!你咋不上天呢-明恒博客

这句 SQL 怎么优化呢?

先看这句 SQL 的写法,其实没有什么大问题。虽然确实可以做一些小的改动,比如把 left join 改成 inner join、或者用用子查询之类的,但是优化效果并不明显。

那下一步,就是掏出数据库优化大杀器 —— 索引 ,从相关面试题的数量,就已经能感受到索引的重要性了。

其实我用的数据库监控平台已经给出了优化建议,正是添加索引:

图片[7]-一句慢 SQL 执行 600 秒?!你咋不上天呢-明恒博客

添加索引最简单的原则就是:需要根据什么字段查询 / 排序 / 连接 / 分组,就可以考虑增加索引。当然,具体情况具体分析,索引的选择需要根据查询条件、表的大小、数据分布等多方面考虑,比如字段值是唯一的、或者值比较分散的字段更适合加索引,而不建议给性别这种值区分度不高的字段增加索引。

所以对于这句慢 SQL,我选择给 message_record 表的 createTime 字段增加索引,然后使用 Explain 语句查看执行计划,会利用到新增的索引:

图片[8]-一句慢 SQL 执行 600 秒?!你咋不上天呢-明恒博客

该加的索引已经加了,但因为主表和子表的数据量就是比较大,查询还是巨慢,怎么办呢?这种情况下,可以先思考能否 先通过业务手段解决 。既然优化不了它,那就干掉它!思考:这句 SQL 能不能不执行?为什么要同时查出这么多用户的消息记录?是不是需求本身就不合理?

如果你把产品经理说服了,OK,愉快摸鱼。

但如果产品经理把你说服了,好吧,那就再考虑下 能不能通过程序优化 ?比如将查询进行拆分,按照更精确的日期(比如 “天”)多次查询消息、或者指定用户 id 来避免联表查询,并且通过多线程同时并发执行查询。当然这样是否有效还是需要验证的。

还有其他的方法:

1)如果查询是需要频繁(或实时)触发的,可以使用 Redis 或内存来缓存数据,避免重复查库。

2)如果查询是定时触发的,可以考虑降低定时任务的执行频率,并且尽量错峰查询,避免这种慢 SQL 在用户使用高峰期执行。

大家看图也能够发现,我们的慢 SQL 主要就是在凌晨出现的,这是由于凌晨用户比较少,我们选择在这个时间点执行一些比较重的定时任务。

图片[9]-一句慢 SQL 执行 600 秒?!你咋不上天呢-明恒博客

如果无法通过程序优化,那么就从数据库下手吧,比如通过分库分表,将消息记录表按天拆分成多个表,提高单表查询效率;或者将已经被逻辑删除的消息移动到另一张表中进行备份,而不是继续存在于主表中,跟清空电脑上的回收站是类似的道理。但分库分表的代价就是有额外的实现成本和维护成本,建议还是慎用。

还有其他的优化方法,比如升级数据库的配置,甚至是更换一个查询性能更高的数据库(比如适用于大数据分析的 ClickHouse),不过成本有点高,反正对于我们小公司百万量级的数据量来说,还没必要考虑。


以上就是本期分享,大家平时自己写项目的时候可能不太注意 SQL 的写法,觉得项目能跑就行。但其实学习 SQL 优化是很有必要的,因为等你进公司后随着业务数据量的增大,有些慢 SQL 会逐渐暴露出问题。不是不报,时候未到而已。

© 版权声明
THE END
我的博客即将同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=270198dipw4ko
点赞13赞赏 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容