本节的主要内容如下:
教程里给出了这么一张图:
S1部分,需要观察服务器的状态是否是周期性的,比如说每个月固定几天慢,或者是每年固定几天慢这种。如果存在这种周期性的波动,那么可能是周期性业务节点的问题,比如说双十一等促销活动。这时候我们可以选择加缓存或者更改缓存失效策略来解决。
如果上一步并没有解决问题,或者是服务器的状态不是周期性的,那么进入S2这一步。
S2部分,需要开启慢查询,来帮助我们定位执行慢的SQL语句。其中,我们通过设置long_query_time
这个参数来定义"慢"的阈值,如果 SQL的执行时间超过了这个阈值,就可以认为是慢查询,会被统一收集起来,做下一步分析。
S3部分,需要对执行慢的SQL语句做进一步分析。通过explain
来查看对应的执行计划,通过show profile
来查看每个步骤的时间成本。结合判断,查询慢是因为执行时间长,还是等待时间长。
如果是等待时间长,则进入A2步骤,调整服务器的参数,比如说适当扩大数据库缓冲池等。
如果是执行时间长,则进入A3步骤,考虑对SQL语句做优化(减少关联表等),或者对涉及到的表做优化(加索引)。
如果A2和A3都不能解决问题,那么可能是数据库自身的性能到瓶颈了,进入A4阶段,开始掏钱,看是否是需要增加服务器或者内存等,是否读写分离,是否分库分表等等。
以上就是数据库调优的完整流程思路,其实总结起来就是三个工具的使用:慢查询、explain
和show profile
慢查询,全称是慢查询日志,它可以帮助我们定位到执行慢的SQL。
使用前,我们需要查看慢查询是否已经开启:
mysql > show variables like '%slow_query_log';
OFF就是没开,可以通过以下方式打开:
mysql > set global slow_query_log='ON';
然后我们通过以下命令,查看慢查询日志文件的位置:
mysql > show variables like '%slow_query_log%';
慢查询里还有一个核心参数,即时间阈值参数,超过阈值的SQL查询才会被认为是慢查询,从而写进慢查询日志里。
可以使用下面命令来查看这个时间阈值参数:
mysql > show variables like '%long_query_time%';
默认情况下是10s,单位是秒。
可以通过下面命令进行修改:
mysql > set global long_query_time = 3;
即将时间修改为3s。
我们可以通过MySQL自带的mysqldumpslow这个工具来统计慢查询日志(是一个perl脚本,需要安装perl)。
只做下简单理解吧。
比如我们想要按照查询时间排序,查看前两条SQL语句,这样写即可:
perl mysqldumpslow.pl -s t -t 2 "慢查询日志路径"
-s t
表示以查询时间来排序,-s
支持多种排序参数,分别是 c(访问次数)、t(查询时间)、l(锁定时间)、r(返回记录)、ac(平均查询次数)、al(平均锁定时间)、ar(平均返回记录数)和 at(平均查询时间。
-t 2
表示返回前两条数据。
了解即可。开启了慢查询日志,并设置了相应的慢查询时间阈值之后,只要查询时间大于这个阈值的 SQL 语句都会保存在慢查询日志中。
之前其实也讲过,explain
用来查看SQL的执行计划。
比如:
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
这里不再详述。
show profile可以进一步看到更详细的解析,包括SQL优化用了多久、统计用了多久、查询用了多久等。
查看profiling是否开启,默认是关闭OFF的:
mysql > show variables like 'profiling';
通过下面指令开启:
mysql > set profiling = 'ON';
查看当前会话下有哪些profiling:
mysql > show profiles;
可以看到当前会话一共有过两个查询,如果想查看最近一个查询的开销,可以使用:
mysql > show profile;
或者查看指定Query ID的开销,比如说查看ID为2的查询的消耗:
show profile for query 2;
或者查看详细信息:
show profile cpu,block io for query 2;
可以看到不同部分的开销,比如CPU、磁盘IO等。
我们可以根据每一部分的执行时间,来判断SQL到底慢在哪里。
不过,show profile
在高版本中即将被弃用,我们现在也可以使用下面这种方式来代替:
select * from information_schema.profiling;
不过这种方式也需要提前将profiling打开,即执行set profiling = 'ON';