阿里巴巴工程师教你认识mysql慢查询
1.为什么聊这个话题
在工作中,我们经常遇到各种线上问题,如cpu 和 load都变高了,full gc频繁,线程池满了等,经过各种排查可能最后有挺多原因是跟数据库出现了慢查询或者不合理的查询导致等一系列等连锁反应。 在各种大促性的活动我们会做各种手段去保证系统的稳定性,如压测,限流,缓存,消息异步化,很多情况下除了计算密集型等应用,很多都是为了防止我们的数据库挂掉。 数据库性能提升是我们能够放心做应用服务器水平扩容的一个最重要的前提。否则如果你的数据库查询性能差的话,一个慢查询就可能导致mysql服务器运行中线程数飙高,cpu飙高,rt延长。进而导致应用服务器的处理线程耗时延长,最终导致线程池满,cpu,load都会飙高。如果依赖你的服务的其它服务器没有做好降级熔断处理,那可想而知,他的应用也会挂掉。这个慢sql就是压死你的最后一棵稻草了。 后面作为一个专题和大家一起探讨聊聊mysql的慢查询和我在工作中遇到的实际问题的案例分享。今天先聊下 慢查询的一些基础和我的一些小套路。
2.查询慢的常见原因
2.1 应用服务端一次性访问过多数据
2.1.1 查询过多行
常见案例:一次从数据库中获取到很多数据,在应用服务器中做排序什么的,最终只取其中很小一部分数据 举个我犯过的一个真实案例:之前有个定时任务需要从数据库中扫描数据并定的处理,当时是分页查询的,当时为了减少对数据库的访问次数,就将一次分页查询返回的条数设置了2万条,且单台应用服务器有多个线程在拉取数据并做处理,记得应该有二三十个线程,后来观察发现服务器开始有频繁的full gc发生了。这个就是服务器本身处理能力有限,却一次性都捞到内存中不断等待被处理。这种情况下数据库本身也有压力,同时应用服务器也承受了他不能承受的。
2.1.2 查询过多列
关于这一点,目前工作中用的不多,大部分情况下我们还是会返回所有列。 大部分情况下为了做到查询接口在应用端的接口复用。不太可能去写多个不同的sql返回不同的列并实现多个不同的接口吧。 另外大部分情况下我们一行的数据大小都是很小的,比如100字节。且本身innodb就是行存储类型,即不管你是需要获取哪些列,最终还是需要在存储引擎层读取一整行的数据,能减少的主要是网络io大小。当然如果你本身只需要返回的列全是索引中的列,且这种查询比较频繁,倒是可以考虑这种优化。减少了本身但回表查询主键索引获取其它列的操作。且网络io本身也减少了。
2.2 mysql服务端访问存储引擎过多数据
2.3 mysql服务端并发访问量大的问题
这种情况比较少见,常常我们理解的慢查询可能都是单条sql本身访问的时候就是很慢。但是有些情况下,单条sql访问一点都不慢,可能10ms一下就返回了,但是当这个sql并发访问量很大,就会导致同一时刻的扫描行数也会很大,这个时候这个sql也本省成为了慢sql。 举一个真实的案例:之前淘宝图片空间我们会需要查询一个商家的所有图片的文件夹记录的情况,大部分情况下一个图用户的图片空间的文件夹的数量其实是很少的,但是却出现了一个时间点并发访问量很大的调用。导致mysql的行扫大增,执行线程数飙高,cpu飙高等一系列现象。 这类慢查询你就无法单纯优化单条sql了,因为他已经索引最优,查询合理了。无法优化了。只能想办法从其它角度减少并发访问量。如增加缓存,及其限流处理。
2.4 mysql同一条记录频繁更新导致的
这种更多的出现在库存更新场景。由于热点商品库存扣减导致的行锁等待造成的。多个线程会同一时间内都在等待行锁这种资源的释放导致。
3. 排查慢查询的套路
第三步、根据查询执行计划确认是否索引设计不合理或者查询语句使用不当等
第四步、索引优化或者修改查询语句