如何使用性能分析工具定位SQL执行慢的原因?

前言

在项目预上线之后,发现有一些SQL执行的很慢,如何排查定位SQL查询慢的原因呢?是索引设计的问题?服务器参数配置的问题?还是需要增加缓存的问题?下面咱们一起就从性能分析来入手,定位导致SQL执行慢的原因。

数据库服务器的优化步骤

当我们遇到数据库调优的问题,该如何思考呢?下面分享一张思考的流程图:
将整个流程划分成观察(Show status)和行动(Action)两个部分。其中字母S的部分代表观察(会使用相应的分析工具),字母A代表的部分是行动(对应分析可以采取的行动)。
在这里插入图片描述
整个过程中通过观察数据库整体的运行状态,借助性能分析工具可以让我们了解执行慢的SQL有哪些,查看具体的SQL执行计划,甚至是SQL执行中的每一步成本代价,这样定位了问题所在,找到了问题再采取相应的行动从而完成数据库的调优。

调优流程图详解:
1、首先在 S1 部分,我们需要观察服务器的状态是否存在周期性的波动。如果存在周期性波动,有可能是周期性节点的原因,如双十一,促销活动等。这样的话,可以通过 A1 加缓存这一步骤解决,或者更改缓存失效策略。

2、如果缓存策略没有解决,或者不是周期性波动的原因,就需要进一步分析查询延迟和卡顿的原因。进入开启慢查询 S2 步骤,通过慢查询可用快速定位执行慢的SQL语句。我们可以通过设置 long_query_time 参数定义“慢”的阈值(阈值即边界值),如果SQL执行时间超过了阈值,则认为是慢查询。收集上来这些慢查询的SQL语句之后,我们就可以通过分析工具对慢查询日志进行分析。

3、在收集到慢查询的SQL语句后,我们可以进一步用Explain去查看对应SQL语句的执行计划,或者使用Show Profile查看SQL中每一个步骤的时间成本。也就是进入 S3 步骤。这样我们就能了解SQL查询慢的原因是因为执行时间长,还是等待时间长。

4、如果是SQL等待时间长,就进入 A2 步骤。进行调优服务器的参数,比如适当增加数据库缓冲池等。
如果是SQL执行时间长,就进入 A3 步骤。可以从三个方面进行优化调整:

  • 索引设计优化。比如联合索引就比多个单个索引的查询效率要快一些。
  • Join表是否过多。Join表的数据最好不要超过三张,表的数据越多,嵌套循环就越多,查询时间也就越长。
  • 数据表设计优化。虽然一般设计数据表都遵循三范式,但是我们可以适当的增加数据冗余度,以空间换取时间提高数据的查询效率。

5、如果 A2 和 A3 都不能解决问题,就要考虑数据库自身的SQL查询性能是否已经达到了瓶颈,如果确认没有达到性能瓶颈,就需要重新检查也就是重复上述步骤。
如果已经达到了性能瓶颈,进入 A4 阶段,需要考虑增加服务器,采用读写分离的架构,或者考虑对数据库进行分库分表,比如垂直分库,垂直分表和水平分表等。

性能分析工具

工欲善其事必先利其器,我们可以采用分析工具帮我们定位有问题的SQL,下面介绍三种分析工具,不过也可以是SQL调优的三个步骤:慢查询、EXPLAIN 和 SHOW PROFILE.

一、使用慢查询定位执行慢的SQL

1、查看状态
我们知道慢查询可用帮我们找到执行慢的SQL,是使用之前先来看一下慢查询是否已经开启,可以在Navicat中使用下面命令进行查看:

show variables like '%slow_query_log';

在这里插入图片描述
执行之后的结果显示是 OFF ,说明此时是关闭状态。我们可以把慢查询日志打开,注意设置变量值的时候需要使用 global ,否则会报错:

set global slow_query_log='ON';

执行完之后再次检查慢查询是否开启,这次显示的是开启状态。
在这里插入图片描述
2、慢日志存储路径
通过下面的命令查看慢日志存放的路径:

show variables like '%query%';

在这里插入图片描述
3、慢查询阈值设置
在查看慢查询日志的存储路径时,我们能看到查询结果中有一个参数 long_query_time,这个参数的值即为慢查询的时间阈值。如果我们想单独查询一下慢查询阈值,可以使用命令:

show variables like '%long_query_time%';

如果我们想把时间缩短为3秒,可以这样设置:

set global long_query_time = 3;

开启慢查询日志,并设置相应的慢查询时间阈值之后,只要查询时间大于这个阈值的SQL语句都会保存在慢查询日志中。

二、Explain查看执行计划

1、Explain返回结果参数介绍
定位了查询慢的SQL之后,然后用Explain工具做针对性的分析。Explain的使用非常简单,在SQL语句之前加上Explain即可,SQL执行结果就会显示所采用的执行计划。
例如:
查看product_comment 和 user 表进行联查所采用的的执行计划:

EXPLAIN SELECT comment_id, product_id, comment_text, product_comment.user_id, user_name FROM product_comment JOIN user on product_comment.user_id = user.user_id 

在这里插入图片描述
Explain可以帮助我们了解数据表的读取顺序,select子句的类型,数据表的访问类型,可使用的索引,实际使用的索引,使用的索引长度,上一个表的连接匹配条件,被优化器查询的行的数量以及额外的信息(比如是否使用了外部排序,是否使用了临时表等)等。
2、数据表的访问类型type参数
数据表的访问类型type参数所对应的type列参数很重要,通过这个参数我们能够了解SQL执行过程中对数据表是如何访问的。

type参数的六种情况:
在这里插入图片描述在这些情况里,all是最坏的情况,因为采用了全表扫描的方式。index和all差不多,只不过index对索引表进行全扫描,这样做的好处是不再需要对数据进行排序,但是开销依然很大。如果我们在extra列中看到显示是Using index,说明采用了索引覆盖,也就是索引可以覆盖所需的select字段(即宽索引),就不需要进行回表,这样就减少了数据查找的开销。

三、SHOW PROFILE查看SQL的具体执行成本

1、查看及修改 profiling 状态
SHOW PROFILE相比Explain能看到进一步的执行解析,包括SQL都做了什么,所花费的时间等。
默认情况下,profiling是关闭的,我们可以在会话级别开启这个功能。
在Navicat执行下面的命令查看状态:

show variables like 'profiling';

通过设置profiling=‘ON’ 来开启show profile:

set profiling = 'ON';

2、查看当前会话有哪些Profiles,使用下面的命令:

show profiles;

在这里插入图片描述
如果想要查看上一个查询的开销,可以使用:

show profile;

在这里插入图片描述

3、查看指定Query ID的开销,比如查询query id为2的SQL语句执行的开销:

show profile for query 2 

在这里插入图片描述通过show profile 我们可以看到每一步的耗时,以及在不同的部分,比如CPU,block.io的执行时间,这样我们就能判断出来SQL到底慢在哪里。

注意:不过show profile 命令将被弃用,我们可以从information_schema中的profiling数据表进行查看。

总结

这篇文章我们一起梳理了SQL优化的思路,首先需要进行观察和分析,找到问题之后对症下药进行调优。常用的分析工具就是这三种:慢查询日志,Explain和show profiling,除此之外实际上可以使用的分析工具还有很多。
最后做一个简单的总结:我们可以通过慢查询日志定位执行慢的SQL,然后通过explain 分析该SQL语句是否使用到了索引,以及具体的数据表访问的方式是怎样的。也可以用show profiling 进一步了解SQL每一步的执行时间,包括I/O和CPU等资源的使用情况。

本文内容参考了极客课程,欢迎大家一起交流学习~

发布了192 篇原创文章 · 获赞 219 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Sophia_0331/article/details/105440151
今日推荐