MySQL慢查询日志默认关闭,需通过SHOW VARIABLES确认并配置slow_query_log=ON、slow_query_log_file和long_query_time;mysqldumpslow用于聚类统计而非单条分析,关注Count、Time、Lock三列,注意其SQL归一化特性及性能开销平衡。

怎么确认 MySQL 慢查询日志开了没
很多问题根本不是分析不出来,而是日志压根没开——slow_query_log 默认是关闭的,连日志文件都没有,mysqldumpslow 再好也读不到东西。
先登录 MySQL 执行:
SHOW VARIABLES LIKE 'slow_query_log';如果返回
OFF,就得去配置文件(通常是 /etc/my.cnf 或 /etc/mysql/mysql.conf.d/mysqld.cnf)里加两行:
slow_query_log = ON-
slow_query_log_file = /var/log/mysql/mysql-slow.log(路径得确保 MySQL 进程有写权限) - 别忘了设阈值:
long_query_time = 1(单位秒,建议先设成 1,上线后按需调低)
改完必须重启 MySQL 或执行 SET GLOBAL slow_query_log = ON;(但后者不持久)。注意:动态开启后,已连接的会话不会自动记录慢查询,新连接才生效。
mysqldumpslow 解析结果怎么看懂
mysqldumpslow 不是“查哪条慢”,而是“聚类统计”。它把相似 SQL 归为一类(比如 WHERE 条件值不同但结构一样),再按出现次数、平均耗时排序。默认输出最慢的 10 条,但实际最有价值的是高频+中等耗时的那几类——它们可能正在悄悄拖垮整体响应。
常用命令组合:
-
mysqldumpslow -s t -t 10 /var/log/mysql/mysql-slow.log(按总耗时排序,取前 10) -
mysqldumpslow -s c -t 20 /var/log/mysql/mysql-slow.log(按出现次数排序,取前 20,常用来发现被滥用的简单查询) -
mysqldumpslow -g "SELECT.*FROM orders" /var/log/mysql/mysql-slow.log(只过滤含指定模式的语句,注意正则语法简单,不支持复杂匹配)
关键看三列:Count(执行次数)、Time(平均/总耗时)、Lock(锁等待时间)。如果 Lock 占比高,大概率是事务没及时提交或索引缺失导致行锁升级为表锁。
为什么 mysqldumpslow 显示的 SQL 看着“不对劲”
常见现象:日志里明明记的是 SELECT * FROM users WHERE id = 123,mysqldumpslow 却显示成 SELECT * FROM users WHERE id = N。这不是 bug,是它的归一化逻辑——所有数字、字符串字面量都会被替换为占位符(N 表示数字,S 表示字符串)。
这意味着:
- 你不能靠它直接复制粘贴到 MySQL 里执行验证;得去原始日志里搜具体语句(用
grep -A 5 "id = 123" /var/log/mysql/mysql-slow.log) - 如果某类 SQL 出现次数极高但单次不慢,可能是应用层循环调用(比如 for 循环里查用户信息),这类问题
mysqldumpslow会合并显示,但根源在代码逻辑 - 函数调用如
NOW()、UUID()也会被标准化,所以带函数的语句容易被误判为“同一类”,实际执行计划可能完全不同
慢查询日志本身有性能开销,怎么平衡
开启慢查询日志不是零成本。每条满足条件的 SQL 都要写磁盘,高并发下 I/O 压力明显,尤其当日志路径在机械盘或与数据文件共用磁盘时。更隐蔽的问题是:如果 long_query_time 设得太低(比如 0.1 秒),日志体积爆炸,mysqldumpslow 解析变卡,甚至影响线上服务。
折中做法:
- 日常监控用
long_query_time = 1,配合log_queries_not_using_indexes = ON(只对没走索引的查询额外记录,不管耗时) - 排查具体问题时临时调低:
SET GLOBAL long_query_time = 0.5;(注意这是会话级变量,只影响新连接) - 定期轮转日志:
mysqladmin flush-logs,避免单个文件过大;配合 logrotate 配置自动压缩归档
真正难的是区分“慢”和“不合理”——一条 800ms 的查询如果只执行一次/天,不如一条 200ms 却每秒执行 50 次的查询危险。盯住频率和分布,比死磕单条耗时更有价值。

















