需检查slow_query_log是否为ON且slow_query_log_file路径可写,再确认long_query_time阈值是否合理;日志不含执行计划,建议开启log_queries_not_using_indexes等增强参数,并用mysqldumpslow聚合分析。

如何确认慢查询日志是否已启用
MySQL 默认不开启慢查询日志,必须手动配置并重启(或动态生效),否则查不到任何记录。关键看两个系统变量:slow_query_log 是否为 ON,以及 slow_query_log_file 指向的路径是否可写。
- 执行
SHOW VARIABLES LIKE 'slow_query_log';确认开关状态 - 检查
SHOW VARIABLES LIKE 'long_query_time';—— 默认是 10 秒,生产环境建议调低到1或0.5,否则多数业务慢 SQL 不会记录 -
slow_query_log_file路径需 MySQL 进程有写权限,常见坑是设成了/var/log/mysql/slow.log,但 mysqld 用户没权限写入 - 若用
SET GLOBAL slow_query_log = ON;动态开启,注意该操作不持久,重启后失效
如何定位某条具体慢 SQL 的执行上下文
慢查询日志(如 /var/lib/mysql/slow.log)里每条记录包含时间戳、用户、锁等待时长、扫描行数、返回行数等,但默认不带执行计划(EXPLAIN)和绑定参数值,仅靠日志很难复现真实性能瓶颈。
- 务必开启
log_queries_not_using_indexes = ON(谨慎开启,可能日志暴增)—— 可捕获“没走索引却扫全表”的隐性慢查询 - 加上
log_slow_admin_statements = ON才能记录ALTER TABLE、ANALYZE TABLE类管理语句 - MySQL 8.0+ 支持
log_slow_extra = ON,会额外输出Query_time、Lock_time、Rows_examined、Rows_sent,便于判断是 IO 瓶颈还是结果集过大 - 日志中出现
# User@Host: app[app] @ [10.1.2.3]表示来源 IP 和账号,结合应用监控可快速定位服务模块
如何用 mysqldumpslow 快速聚合分析慢日志
原始慢日志文件大且重复多(比如同一 SQL 带不同参数反复出现),直接 grep 效率低。mysqldumpslow 是 MySQL 自带的聚合工具,能按模板归类、排序统计。
- 常用命令:
mysqldumpslow -s at -t 10 /var/lib/mysql/slow.log—— 按平均查询时间倒序取 Top 10 -
-s c按出现次数排序,-s ar按平均扫描行数排序,-g "SELECT.*users"可正则过滤 - 注意:该工具会把带不同字面值的 SQL 视为不同语句(如
WHERE id=1和WHERE id=2),除非开启--verbose并配合pt-query-digest - 若日志含微秒级时间(MySQL 5.6.11+ 默认),确保用对应版本的
mysqldumpslow,否则解析失败报错Unknown suffix '.'
为什么开了慢日志却看不到预期的慢 SQL
最常被忽略的是 SQL 执行时间未超 long_query_time 阈值,或者被优化器重写后实际执行很快;还有些情况是日志本身被轮转或清空了。
-
long_query_time是按「SQL 执行完成」计算,不含网络传输、客户端解析时间;存储过程内多条语句只记最后一条耗时 - 主从复制中,从库的慢日志只记录
SQL_THREAD执行的 relay log 内容,不记录从库上主动执行的语句 - 使用连接池(如 HikariCP)时,
SET SESSION long_query_time = 0.1;可临时降低当前连接阈值,避免全局调整影响其他业务 - 某些 ORM(如 MyBatis)会自动加
/* ApplicationName=xxx */注释,这类语句仍会被记录,但需在日志中识别注释前缀才能关联到服务名
慢查询日志只是起点,不是终点。真正卡点往往藏在 Rows_examined 和 Rows_sent 的比值里——如果扫了 10 万行只返回 1 行,说明索引没用对,而不是单纯“SQL 太慢”。










