如何开启并确认 MySQL 慢查询日志是否生效
慢查询分析的前提是日志得真正写进去。很多人配置了
slow_query_log = ON和
long_query_time = 2,但查不到日志,根本原因是没指定
slow_query_log_file路径,或者 MySQL 进程对目标目录无写权限。
实操建议:
用SHOW VARIABLES LIKE 'slow_query_log%';确认三项关键变量:是否启用、日志路径、阈值 路径必须是 MySQL 进程用户(如
mysql)可写的绝对路径,例如
/var/log/mysql/mysql-slow.log,不能是相对路径或家目录
long_query_time默认是 10 秒,生产环境建议设为
1.0或
0.5;注意它只对执行时间 ≥ 阈值的语句生效,不包含锁等待时间(除非开启
log_queries_not_using_indexes) 动态开启需执行
SET GLOBAL slow_query_log = ON;,但重启后失效;永久生效要写进
my.cnf的
[mysqld]段
用 mysqldumpslow 快速定位高频/高耗时 SQL
mysqldumpslow是 MySQL 自带的轻量级分析工具,适合快速筛出“最慢的 10 条”或“出现最多的 5 条”,比直接
grep日志高效得多。
常见组合用法:
mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log:按总执行时间排序,取前 10 条
mysqldumpslow -s c -t 5 /var/log/mysql/mysql-slow.log:按出现次数排序,看哪些 SQL 被反复执行
mysqldumpslow -g "SELECT.*FROM orders" /var/log/mysql/mysql-slow.log:过滤含特定模式的慢查询(注意正则语法简单,不支持复杂匹配)
注意:
mysqldumpslow会自动归一化 SQL(比如把
WHERE id = 123变成
WHERE id = N),所以统计的是“模板维度”的频次,不是原始语句条数。
pt-query-digest:精准分析 + 索引建议的核心工具
Percona Toolkit 的
pt-query-digest是业界事实标准,它能解析慢日志、聚合统计、识别全表扫描、估算索引收益,还能输出可读报告和优化建议。
典型使用流程:
基础分析:pt-query-digest /var/log/mysql/mysql-slow.log只看最耗时的 3 条 SQL 及其执行计划:
pt-query-digest --limit 3 /var/log/mysql/mysql-slow.log结合
EXPLAIN分析某类慢查询:
pt-query-digest --explain h=127.0.0.1,u=root,p=xxx /var/log/mysql/mysql-slow.log(需确保账号有
PROCESS权限) 输出 HTML 报告便于分享:
pt-query-digest --report-format html /var/log/mysql/mysql-slow.log > slow-report.html
关键点:它默认只分析
Query类型语句,若日志里有
Connect、
Quit等非查询事件,需加
--filter '$event->{fingerprint} =~ m/^select|^update|^insert|^delete/' 过滤。
为什么 explain 显示 type=ALL 却没走索引
这是调优中最常被误判的点——
EXPLAIN输出
type = ALL表示全表扫描,但未必是“没建索引”,更可能是索引失效或优化器误选。
排查优先级:
检查WHERE条件字段是否在索引最左列,比如索引是
(a,b,c),但查询写了
WHERE b = 1,就无法使用该索引 确认字段类型是否隐式转换:比如
user_id是
INT,但 SQL 写成
WHERE user_id = '123',会导致索引失效 查看
key_len是否符合预期,若远小于索引定义长度,说明只用了部分列 用
ANALYZE TABLE table_name;更新统计信息,避免优化器因过期数据误判 必要时强制指定索引:
SELECT * FROM t USE INDEX (idx_a_b) WHERE a = 1 AND b = 2;,再对比执行时间
真正难调的,往往不是缺索引,而是复合条件下的索引覆盖、排序字段顺序、以及
ORDER BY + LIMIT场景下优化器放弃索引选择文件排序。
