有一个mysql查询场景:

  • 单表数据量不会太大,总数量在几万条近十万
  • 有一个status字段,取值可能为0、1、2,初始为0,后续会变为1、2
  • 绝大多数数据的status为2,少量为0
  • 查询场景是会不断的查出status为0的数据来进行处理

之前开发想着总数据量就这么点,status为0的数据也不多,根据status查询的时候性能不至于太低,就没建索引硬查了。

然鹅,在测试环境跑了一段时间后,mysql告警了,cpu爆炸了。上日志平台查看,找到了一些慢查询,就是简简单单的,上面的select。

写代码用的是orm框架sequelize,就是一个简单的findOne。
对应的慢查询:

image.png

一个select语句耗时3s,而且整张表里边其实一条数据status=0的数据都没有,全部是status=2的数据。这里把status换成2之后,耗时立马变成了瞬间完成。

分析一下执行过程:
image.png

发现进行了全表扫描。

同样是全表扫描,status=2时,因为全部都是满足条件的数据,扫到第一条就返回了,所以速度很快。
status=0时,则会真的扫完全表都找不到记录,返回empty set。

这里仔细分析了一下,数据量也不大全表扫描也不至于3秒,后来挨个看字段,想起了在status=2时,result里边会被塞入大量的结果,其本身是一个mediumtext字段。

试验一下,只select id,全表扫描的速度也立马起来了!耗时在十来毫秒。而像上面一样加入result字段后,整个查询就变成了慢查询。

这里加个索引可以更快,给status加上索引

image.png

经验:

  1. 当表里有大尺寸数据的字段存在时,要格外关注查询性能
  2. 项目测试阶段要对mysql表索引是否合理,进行排查

☞ 参与评论