加载中...
mysql索引导致慢查询
发表于:2023-01-10 | 分类: 开发常见问题
字数统计: 1.1k | 阅读时长: 3分钟 | 阅读量:

背景描述:

下午突然接到用户反馈生产环境某个页面响应很慢,已经影响到用户使用,经简单调查发现是后端一个接口请求后响应数据返回的很慢,遂调查原因并修复

调查流程

观察链路,定位问题

由于是微服务系统,第一反应就是先观察调用链路,定位耗时操作发生的位置,链路结果如下图(仅粘贴了部分耗时操作结果):

链路结果.png
根据图中结果来看,一个请求中执行了很多次的数据库查询,并且每次数据库查询耗时都很高,平均在300-400ms,最严重的时候一次查询都要1000ms以上。
以此来看有两个优化点: 1. 减少查询次数, 2. 降低查询耗时
减少查询次数可能需要修改代码逻辑,并进行业务和回归测试,不能作为临时解决问题的方案,但可作为后续代码性能优化的方案(看来需要重视代码review和压力测试)
既然第一点走不通,那就只能走第二点了,想办法降低查询耗时!

查看sql,定位查询耗时原因

根据链路信息,发现查询耗时的sql如下图所示(涉及业务已打码),将该sql取出,手动在UAT环境执行
链路sql.png
UAT环境数据量基本与生产环境相同,执行sql 结果如下:
未索引执行速度.png
耗时达到了惊人的500ms, 看来是sql产生了慢查询

调查慢查询sql发生的原因

出现慢查询,第一件事就是看一下这条sql的执行计划:
未索引执行计划.png
到这里,慢查询的原因基本清晰了: 这条sql触发了全表扫描,在两万多条数据中过滤一条结果….
于是,我们来看一下这个表的配置,发现该表只有一个主键作为索引,但是根据sql来看,该表查询数据过滤条件并不是主键,与业务和开发人员确认后,发现该表经常用来作为过来条件的并不是主键列,而是另外的两个列,于是我们查看了一下该表对于这两个列的处理:
没有索引的表.png
看到这,问题基本清晰了: 业务中的一条sql在查询的时候由于没有索引导致慢查询发生,且该接口多次进行该业务查询导致接口响应时间变长.

解决问题

既然已经定位到是由于索引导致了全表搜索,那么就在该表对应的列建立索引即可,具体索引建立方案需要根据业务情况自行决定,我这里该表经常使用的是a列单独搜索或a+b列联合搜索,于是我在该表建立了两条索引,一条是a列索引,另一条是a+b的联合索引(注意索引顺序与查询顺序,避免索引失效)
建立索引.png

问题验证

索引建立后,再次进行执行计划的查看,发现不再发生全表扫描,已经开始使用索引查询了:
索引后执行计划展示.png

然后我们再来执行以下这条sql 看看耗时怎么样
索引后速度.png
耗时基本控制在20ms以内,速度提升了几倍

生产调试验证

由于是生产环境,考虑到建立索引时对数据库性能影响较大,故需要选择一个用户比较少的时间进行调整
调整后链路结果如下:
优化后执行链路.png
无论是内部调用还是客户端调用,时间均可控制在150ms以内,问题临时得到解决。
注: 增加索引只是临时解决了该问题,随着数据量的增加查询时间还是会变长(但是不会像上面那么离谱),出现该问题最主要的原因是业务代码中大量重复查询数据库的操作,最优方案是建立索引后,业务代码也进行相应的优化.

总结:

  1. 平时开发时需要多考虑代码执行流程,尽量避免大量的其它系统交互和时间复杂度
  2. 团队中的code-revirew的重要性
  3. 要根据业务和代码的执行逻辑对数据库表做好设计(包括但不限于表结构、索引、表空间等)
  4. 要有一套完整的应用监控体系方便快速排查问题
上一篇:
clodflare Rest API 实现动态域名更新(DDNS)
下一篇:
搭建openvpn实现外网访问内网资源
本文目录
本文目录