必须先验证三件事:SHOW VARIABLES LIKE 'slow_query_log' 返回ON;SELECT @@global.slow_query_log 和 @@session.slow_query_log 均为1;执行SELECT SLEEP(2)后SHOW GLOBAL STATUS LIKE 'Slow_queries'值+1,否则日志未真正生效。

确认 slow_query_log 是否真正在记录查询
很多线上环境其实根本没开慢日志,或者开了但路径不可写、阈值设太高,导致你翻了半天日志却全是空的。别急着分析,先验证三件事:
-
SHOW VARIABLES LIKE 'slow_query_log'返回必须是ON(不是1或空字符串) -
SELECT @@global.slow_query_log和SELECT @@session.slow_query_log必须都为1;如果 session 是0,说明当前连接不记日志,得新开终端重连 -
SHOW GLOBAL STATUS LIKE 'Slow_queries'初始值应为0,执行一次SELECT SLEEP(2)后必须 +1,否则链路断在中间 - 检查
slow_query_log_file路径父目录权限:ls -ld $(dirname /var/lib/mysql/mysql-slow.log),确保 MySQL 进程用户(如mysql)有写权限;Windows 下注意 UAC 或 XAMPP 安装路径拦截
long_query_time 设多少才抓得到真实瓶颈
默认 10 秒对 Web 服务毫无意义——接口超时通常在 2 秒内,等它进慢日志早就炸了。但设太低又会日志爆炸,关键在平衡:
- 先设
1.0观察 1–2 小时,用mysqldumpslow -s t -t 10 /path/to/slow.log看实际耗时分布 - 若发现大量
0.8–1.2秒的聚合查询,再下调到0.5;注意SET GLOBAL long_query_time = 0.5后必须退出重连,旧连接仍按老值判断 - 避免设
0:它会记录所有查询(包括SELECT 1),磁盘 IO 和文件体积飙升,仅限临时诊断 - MySQL 5.7 及以前版本对小数精度支持有限,
0.098秒可能被截成0.09秒而不触发记录
log_queries_not_using_indexes 不是打开就完事
这个开关一开,所有没走索引的查询都会进日志,但其中大量是低危害噪音(比如 WHERE id = -1 扫 1 行也记),反而掩盖真正问题:
- 必须同步设置
min_examined_row_limit = 100(或更高,如500),表示“未走索引且扫描行数 ≥ 100 才记录” -
min_examined_row_limit在部分云厂商定制版中不支持动态设置,得写进my.cnf并重启 MySQL -
log_queries_not_using_indexes = ON是为了抓“隐性慢”——SQL 很快但本不该快(缺索引),它不能替代long_query_time,两者定位的问题类型不同
从日志里一眼识别瓶颈在哪
慢日志不是纯 SQL 列表,每条记录自带诊断线索,重点盯这三项:
-
Rows_examined远大于Rows_sent?比如扫了 50 万行只返回 10 行,大概率WHERE条件没走索引,或者索引选择性差 -
Lock_time高(如 > 100ms)?说明被其他事务阻塞,不是 SQL 本身慢,得查锁等待链,而不是优化语句 - 日志里出现
Using filesort或Using temporary?执行计划已退化,对应 SQL 的ORDER BY或GROUP BY字段大概率没覆盖索引 - 别直接复制日志里的 SQL 去跑——它常带换行符、反斜杠转义或注释,先粘到编辑器里清理格式再
EXPLAIN
真正的难点不在开启日志,而在区分“慢是因为 SQL 写得差”,还是“慢是因为被锁住”“慢是因为数据量突增但执行计划没变”。Rows_examined 和业务时间点交叉比对,往往比单纯看耗时更可靠。



















