Mysql慢查询——查询优化

Johnson 小试牛刀

在一些公司的面试题中,可以经常看到有这么一道MySQL的面试题:对于SQL查询慢的问题你要怎么去发现和解决。最初我也大概只能回答个索引相关的,比如"通过EXPLAIN查看查询的访问类型和一些查询情况", "查看是否可以在某些表的字段增加索引然后改写查询语句"等,网上的八股也很少提及这个问题,所以我还是去阅读了一下《高性能MySQL》,通过阅读后,我也大致地了解了查询的一些问题所在以及优化的方法,这篇文章便是我针对这本书第六章内容的一些整理总结(其实就是相当于摘抄吧 😤 )。方便自己记忆的同时也放到博客上来给博客更新一下(其实是都放到本地没怎么上传到博客,属于是懒🐶了)

为什么查询慢

​ 在我们看待这个问题的时候,我们就要想:是什么造成SQL的查询慢呢,通过对索引的学习我们也知道索引对于高性能的重要性,但光有索引也是不够的,查询语句的合理性也是要考虑的,如果一个查询语句写的很烂,即使我们的表结构和索引设计的再好,那也是无济于事的。

​ 查询的生命周期大致可以这么来看:客户端发送请求到服务器👉服务器进行解析👉生成执行计划👉执行👉返回结果给客户端。一个查询会在一个生命周期内涉及到这些个任务,而每个任务的完成时间也是不同的。我们可以针对这么一个大概的生命周期概念,来对我们的查询进行一个优化。

优化查询访问

​ 查询性能低一个最基本的原因是我们访问的数据太多,针对查询数据多这一问题,我们可以看看是否有存在这么两个问题:是否查询了很多我们不需要的数据MySQL的服务器是否在分析大量超过我们需要的数据

是否查询了很多不需要的数据

​ 我们通常会认为MySQL返回的是我们需要的数据,但实际上MySQL是先返回全部的结果集再进行计算,所以我们有时候要考虑我们是否真的需要这么多数据呢,就好像我们要让一个页面显示10条数据,我们就要先查个100条数据然后再选前10条展示吗,显而易见是不用的,我们加个 limit 即可。

​ 对于select *的写法我们也要在使用的时候去想我们是否真的需要去使用它呢,对于一些开发者来说,在知道其性能影响的情况下,这样的写法可以简易开发和做到代码复用,是值得考虑的。select *会使得优化器无法完成索引覆盖扫描这类的优化,也会给服务器带来额外的IO、内存和CPU的消耗,在不需要select *的时候它便会给我们造成本没有的性能影响了。

​ 也有这么一种容易发生的情况,就是我们多次重复执行了相同的执行并且返回相同的数据,对于这样的数据,我们可以在第一次查询该数据时将其缓存起来,这样后面再需要时直接从缓存中获取即可。

MySQL是否分析扫描额外的数据

​ 当我们确认我们查询返回的确实是我们需要的数据后,我们就应该看看查询为了返回结果是否扫描了过多的数据。通常简单的衡量查询开销的指标是:响应时间,扫描行数,返回行数,这三个指标都记录在了MySQL的慢日志中,所以检查慢日志记录是扫描行数过多的查询的好办法

​ 如果我们的查询扫描了大量的数据却只返回很少的行,可以考虑如下的优化方式:

  • 使用索引覆盖扫描,使存储引擎不需要回表即可返回结果
  • 改变库表结构
  • 重写这个复杂查询

重构查询方式

​ 如果我们的查询的列确实是需要的,索引的设计和库表的设计也没什么问题的时候,那么就可以考虑下更改我们的查询方式。对于一个大查询,我们可以考虑对它进行分而治之的方法来进行多个小查询。对于一些关联查询,我们也考虑是不是能对它进行分解,就像书上的例子那样:

image-20220817170821072

​ 这样可以让缓存的效率更高,因为有缓存,我们可能可以跳过某条查询或者减少IN()里的内容。也可以减少了锁的竞争。这样的查询也可能能提升查询效率,IN()让MySQL按照ID顺序进行查询,顺序IO是要比随机IO高效的。这样还可以减少冗余记录的查询,在数据库上关联查询我们就可能需要重复访问同一数据,在应用层上进行关联让我们可以对某条数据只查询一次,减少了网络和内存的消耗。

上面所讲的是针对查询的访问和方式,但如果知道MySQL如何优化和执行查询时,那我们在优化查询时便可以按照一些原则让优化器能按我们设想的方向运行。下面这张图是发送一个请求时MySQL所做的事情:

image-20220817172702465

图中的查询缓存在MySQL8已经是关闭的了,《高性能MySQL》所基于的版本还是5版本的,所以如果是8版本或以上的是可以忽略掉查询缓存的。书上在查询优化做了很多的篇幅进行讲解,讲了很多优化器在一些查询上的优化细节和做法,这部分如果放上来记录的话篇幅还是挺长的,多到我也不知道怎么整理写上了比较好,所以第六章的查询优化处理这块还是很建议大家去阅读原书的,在这里我就先不写着了。

总结

​ 一个高性能的查询,需要好的库表设计、索引设计、查询语句设计和查询的优化方式,而查询的优化设计又是很多细节的,所以当SQL查询慢的原因是由于我们查询语句设计不妥当时,便可以照着该书籍第六章的方法去进行优化。

​ 通过网上资料的搜索SQL查询慢的原因也可能不在于查询语句的问题,比如网络不好的情况下,客户端和服务端之间的连接和传输受到影响、IO吞吐量小、缓存不够、出现死锁等等,硬件软件都会或多或少的影响到查询,还是要针对特定的原因去寻找对应的解决办法的。对于我个人来说,排插SQL查询慢的基本方向是通过查询慢日志来定位慢查询SQL,然后通过explain命令去分析该SQL的执行计划后进行相应的优化,如果优化完还是查询慢或者没有什么优化方向后,就再去考虑网络、内存、服务器和应用程序设计上的问题。

  • 本文标题:Mysql慢查询——查询优化
  • 本文作者:Johnson
  • 创建时间:2022-08-17 18:11:19
  • 本文链接:https://iconson.top/Mysql慢查询——查询优化/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论