环境信息
OS
: macOS 14.1.1 (23B81)Docker
: 24.0.5Image
: mysql:8.0.21
慢查询定位
定位慢查询问题,可以通过如下几个步骤进行:
- 开启慢日志;
- 使用慢日志查询分析管理工具;
- 基于已有的慢日志分析,对系统本身做优化。
开启慢日志
如何开启慢查询日志
1、查看慢查询日志是否开启
因为开启慢查询日志是有代价的(跟bin log
、optimizer-trace
一样),所以它默认是关闭的。
开启慢日志,执行命令:
1 | show variables like 'slow%'; |
可以看到slow_query_log
属性是OFF
,处于关闭状态,那么我们需要先开启慢查询。slow_query_log_file
表示慢查询日志文件的存放路径,我们可以自定义文件路径(mysql
安装、运行在docker
):
1 | set global slow_query_log_file = '路径' |
开启慢查询日志
执行命令:
1 | set global slow_query_log = on |
然后再查询一下,发现slow_query_log
处于开启状态:
1 | show variables like 'slow%'; |
开启了之后,是不是所有的查询都会记录在文件里呢?
当然不是,慢查询日志,顾名思义是只记录查询比较慢的语句,那问题又来了,怎么才算查询比较慢的语句呢?
实际上,这里会有一个标准值,而且这个标准值是可以由我们自己设定的。
慢查询的临界值设定
首先查看一下默认的临界值。
执行命令:
1 | show variables like '%long%'; |
其中有一个long_query_time
属性,它的值为10.000000
。它表示的意思是,只记录查询时间在10s
以上的语句。
显然10s
我们是不可接受的,所以需要自己设定一下这个值。因为我的测试表中没有多少条数据XD
,查询很快,所以这里把慢查询的临界值设置为1.00
:
1 | set long_query_time=1.00; |
可以看到现在临界值是1.00
秒了。
1 | +----------------------------------------------------------+----------+ |
现在来模拟手动触发一个大于 1.00s
的慢查询(测试表中没有多少条数据,就直接用sleep
测试了),看是否都记录在了慢查询日志中。
1 | SELECT sleep(3); |
查看慢查询日志当中有多少条记录:
1 | show global status like '%Slow_queries%'; |
看下慢查询日志(mysql
安装、运行在docker
):
1 | docker exec -it d1673994303e cat /var/lib/mysql/d1673994303e-slow.log |
可以看到刚才模拟查询的日志,从该日志中能看到如下几个信息(根据不同的MySQL
版本或者配置,这些信息可能有增减):
产生时间(Time
):2021-03-12T08:52:54.227174Z
来源(User@Host
): df-test[df-test] @ [192.168.65.1]
,即用户 df-test
在192.168.65.1
这个机器上执行了这个查询
查询统计(Query_time
):如消耗的时间,发送/接收的行数
具体的SQL
语句
需要注意的是,上面的操作是在命令行中进行的,如果数据库进行重启,这些设置都会失效。
一般不建议长期开启慢查询日志,如果要永久生效,需要修改配置文件:
1 | vim /etc/mysql/my.cnf |
在配置文件中加上这三行就可以了,但需要重启MySQL
才能生效!
使用慢日志查询分析管理工具
有了慢查询日志,怎么去分析统计呢?比如SQL
语句的出现的慢查询次数最多,平均每次执行了多久?人工肉眼分析显然不可能。
可以通过MySQL
官方自带的mysqldumpslow
工具进行分析,执行命令(mysql
安装、运行在docker
):
1 | docker exec -it d1673994303e mysqldumpslow --help |
例如:查询用时最多的10
条慢SQL
语句:
1 | docker exec -it d1673994303e mysqldumpslow -s t -t 10 -g 'select' /var/lib/mysql/d1673994303e-slow.log |
Count
: 代表这个 SQL 执行了多少次;Time
: 代表执行的时间,括号里面是累计时间;Lock
: 表示锁定的时间,括号是累计;Rows
: 表示返回的记录数,括号是累计。
官方文档地址。
慢查询语句解析
通过慢查询日志,针对性的去找到这些慢查询日志去进行explain
分析 然后去调优创建索引。
执行命令:
1 | explain (SQL语句)。 |
把上面执行的两条语句放一起对比解析一下:
1 | explain SELECT sleep(3); |
需要重点关注possible_keys
、key
、rows
这几个属性值。possible_keys
表示该语句可能会用到的索引key
表示该语句实际用到的索引rows
表示该语句扫描的行数
通过这些属性,可以大致的分析定位到慢查询的原因,然后针对性的去解决。
开启性能详情
如果通过explain
语句解析没有定位到问题,该加的索引也加了,但是还是比较慢,那就可以通过性能详情来进一步的探究一下原因。
性能详情可以追踪查询语句的整个生命周期的状态,有了这些状态值,就可以从更深层次找出具体是哪个环节慢了,从而能针对性的进行改善。
查看性能详情是否开启
执行命令:
1 | show variables like '%profiling%'; |
可以看到profiling
属性值为OFF
,表示关闭。
开启性能详情,执行命令:
1 | set profiling = on; |
当我们开启了之后,在数据库上执行的任何的SQL
语句都会被记录来。
查看性能记录
我们执行一条SQL
语句:
1 | SELECT sleep(3); |
然后查看性能记录:
1 | show profiles; |
可以看到开启后的所有查询语句的记录。我们想查看一下第二条执行语句的整个执行周期的状态详情(SQL
慢要么是CPU
计算复杂,要么是IO
频繁开销所以只看CPU
和block io
即可):
执行命令:
1 | show profile cpu,block io for query 2; |
可以看到整条SQL
语句执行过程每个状态的耗时情况。然后定位到具体是哪个状态最耗时,然后针对性的排查原因。
官方也给出了每个状态的解释,具体可查看官方文档地址。
总结
以上是定位MySQL
慢日志查询问题的步骤总结。在实际应用过程中,要多尝试不同维度的解决方案,并结合自身所处行业、业务等特点,挑选适合自己和团队使用的数据库分析工具,保障系统和业务的稳定。
以上。