必须同时配置slow_query_log=ON、slow_query_log_file绝对路径(MySQL用户有写权限)和long_query_time阈值才生效;SET GLOBAL仅对新连接临时有效,持久化需写入my.cnf并重启。

慢查询日志开关和阈值怎么设才生效
MySQL 默认关闭慢查询日志,光开 slow_query_log 不够,必须同时指定 long_query_time 和日志文件路径。5.6+ 版本还要求 slow_query_log_file 存在且 MySQL 进程有写权限,否则启动时静默失败,日志根本不会生成。
-
SET GLOBAL slow_query_log = ON;仅对新连接生效,重启后丢失;要永久生效得写进my.cnf的[mysqld]段 -
long_query_time单位是秒,支持小数(如0.1),但注意:5.7+ 默认以微秒精度统计,而该参数仍按秒比较——实际判断逻辑是「执行时间 ≥ 设置值(秒)」 - 如果用的是 Percona Server 或 MariaDB,
log_queries_not_using_indexes可额外记录没走索引的查询,但会显著增大日志量,线上慎开
日志格式选 general_log 还是 slow_log?别混用
很多人误以为开启 general_log 就能替代慢日志,其实二者定位完全不同:general_log 记所有语句(含连接、断开),体积爆炸且不含执行耗时;slow_query_log 只记超时 SQL,并附带 Query_time、Lock_time、Rows_sent 等关键指标,这才是性能分析的基础。
- 不要同时打开
general_log和slow_query_log做“双重保险”——general_log会干扰慢日志的语义,且无法过滤 - 日志内容里
Rows_examined比Rows_sent更值得关注:前者反映扫描行数,直接关联索引效率;后者只是返回客户端的行数 - MySQL 8.0+ 支持将慢日志输出到表(
slow_query_log_file = 'mysql.slow_log'+log_output = 'TABLE'),但表方式不支持mysqldumpslow工具,排查反而更麻烦
如何确认慢日志真正在记录?别只看配置项
配置写完不等于生效。常见假阳性:配置已加,SHOW VARIABLES LIKE 'slow_query_log' 显示 ON,但日志文件空空如也——大概率是权限、路径或 SQL 实际执行时间没达标。
- 手动触发一条明确超时的 SQL 测试:
SELECT SLEEP(2);(前提是long_query_time≤ 2) - 检查日志文件属主是否为
mysql用户:ls -l /var/lib/mysql/mysql-slow.log,不是则chown mysql:mysql - 查看错误日志(
error_log)是否有类似Could not write to slow log的报错,这是最直接的线索 - 注意:存储过程内嵌的 SQL 不会单独记入慢日志,只有调用该过程的那条语句可能被记录(取决于过程整体执行时间)
分析慢日志时最容易忽略的三个字段
拿到日志后,多数人只扫 Query_time,但真正定位瓶颈得盯住另外三个字段:
-
Lock_time:锁等待耗时。如果它占Query_time大头,说明是行锁/表锁争用,不是 SQL 本身慢 -
Rows_examined:扫描行数。比Rows_sent高几个数量级?大概率缺索引或索引失效 -
Rows_affected(DML 语句才有):比如UPDATE影响 1 行却Rows_examined是 10 万,说明 WHERE 条件没走索引
真正难的不是打开日志,而是区分“慢在执行”还是“慢在等待”,这得靠三个字段交叉看。没关注 Lock_time 和 Rows_examined 的分析,基本等于只看了半张病历。


















