关于MySQL慢查询阈值的配置,许多DBA和开发者都曾被看似简单的参数设置“坑”过。配置步骤本身并不复杂,但真正容易出问题的,往往是那些文档里不会写、生产环境却总会遇到的细节。本文将从配置链路入手,逐层拆解,并把那些容易踩的坑一一说清楚。
先说一个有些反直觉的判断:并非所有设置了 long_query_time 的 MySQL 实例都会自动记录慢查询。不少团队配置完成后查不到日志,就怀疑参数配错了,但实际上问题往往出在那些你根本没想到的地方。
首先,你需要确认 MySQL 当前的真实状态。不要猜测,直接查询。默认情况下,无论是 Percona 还是官方二进制包,slow_query_log 都是关闭状态,long_query_time 默认为 10 秒——这个值对于线上业务基本等于没开启。因此第一步,执行以下三条命令核实情况:
SHOW VARIABLES LIKE 'slow_query_log';若返回OFF,则日志根本不会写入,调整任何阈值都无效。SHOW VARIABLES LIKE 'long_query_time';注意观察返回值类型:如果显示整数10,说明之前设置的是整数,MySQL 会直接忽略;只有写成1.0这样的浮点数才生效。SHOW VARIABLES LIKE 'slow_query_log_file';确认日志文件路径是否存在,MySQL 用户是否有写权限。此外,SELinux 或 AppArmor 这类安全模块也可能悄悄拦截写入操作。
完成这些基础检查后,下一步就是持久化配置。SET GLOBAL 命令只能做到临时生效,MySQL 一旦重启就会丢失。生产环境必须将配置写入文件系统,否则机器重启导致监控断档,可能引发事故。
编辑 /etc/my.cnf(或 /etc/mysql/my.cnf),在 [mysqld] 段落添加如下内容:
slow_query_log = ON——建议直接写ON,不要写成1或TRUE,部分旧版本只识别ON。slow_query_log_file = /var/log/mysql/mysql-slow.log——显式指定路径,避免使用默认路径时出现权限问题。long_query_time = 1.0——务必带上小数点,1会被当作整型丢弃。- 可选但推荐:
log_queries_not_using_indexes = ON——该开关可以帮助发现大量缺失索引的查询,但日志量会急剧上升,建议先观察一段时间再决定是否长期开启。
保存后用 systemctl restart mysqld 重启服务。注意,单纯执行 reload 是不够的,必须完整重启才能生效。
到这里,很多人的困惑出现了:配置都按步骤做了,也重启了,为什么慢查询日志始终为空?
这类问题,参数本身很少背锅。常见的原因其实很直白:
- 日志文件的父目录不存在,或者 MySQL 进程用户(通常是
mysql)没有写入权限。解决方案很简单:sudo mkdir -p /var/log/mysql && sudo chown mysql:mysql /var/log/mysql。 - 路径使用了相对路径(例如
./slow.log),MySQL 会解析到datadir目录下,容易造成路径误判。 - SELinux 或 AppArmor 拦截了日志写入。可用
setenforce 0临时关闭测试,或者直接查看 audit 日志定位问题。 - 主从架构中,主库在高写入压力下开启慢查询日志可能拖慢 IO。行业经验是:仅在从库开启慢日志,主库保持关闭状态。
最后聊一个很多人容易忽略的点:long_query_time 到底统计的是什么?
该参数统计的是语句“执行完成耗时”,注意它不包含锁等待时间、网络传输时间、FLUSH TABLES 等阻塞操作的耗时。因此,当你看到某条 SELECT 花了 2.4 秒,不一定就是 SQL 本身慢。需要结合 performance_schema.events_statements_summary_by_digest 表中的 avg_timer_wait 和 sum_lock_time 进行对比分析。
阈值设置也并非越小越好,关键在于对齐业务的响应时间基线:
- 新上线服务建议从
1.0开始,运行一周后观察日志量和数据库 CPU/IO 压力。 - 如果核心接口的 P95 响应时间在 300 毫秒级别,则阈值应调整到
0.3。 - MySQL 5.7 及以上版本支持微秒精度(例如
0.15),但旧版本会向下取整到秒,设置了也等于没设置。
还有一个容易被忽略的要点:慢查询日志是纯文本追加写入的,没有结构化时间戳,而且存在刷盘延迟和可能出现截断。不要指望通过 tail + awk 来做实时峰值告警——那不是监控,那是碰运气。

