MySQL开启慢查询日志需设置slow_query_log=ON并调低long_query_time(如0.2),确认生效用SHOW VARIABLES LIKE 'slow_query_log';日志路径权限不足会导致静默失败。
MySQL 怎么开启慢查询日志并确认是否生效
慢查询日志是定位耗时 sql 的第一道入口,但很多人开了配置却没看到日志,根本原因是 slow_query_log 没真正启用,或 long_query_time 设得太高(默认 10 秒),业务里跑个 300ms 的查询都进不去。
- 先确认是否已开启:
SHOW VARIABLES LIKE 'slow_query_log';
返回ON才算生效;如果为OFF,需在配置文件(如/etc/my.cnf)中加slow_query_log = ON并重启,或运行SET GLOBAL slow_query_log = ON;(注意:后者重启后失效) -
long_query_time建议设为0.2(200ms),尤其在高并发 OLTP 场景下,1.0已经太宽松 - 日志路径由
slow_query_log_file控制,默认可能写到/var/lib/mysql/hostname-slow.log,但 MySQL 进程必须对该路径有写权限,否则静默失败——查不到日志时优先检查这个
如何快速从慢日志里提取真实耗时最高的 SQL
直接用 mysqldumpslow 或 grep 翻日志容易漏掉关键信息:比如同一条 SQL 因参数不同被记录多次,或执行时间被格式化成“Query_time: 00:00:01”这种难排序的写法。
- 用
mysqldumpslow -s t -t 10 /var/lib/mysql/xxx-slow.log:其中-s t表示按总耗时排序,-t 10取前 10 条,比手动sort | head更准(它会自动归并带问号参数的相似语句) - 如果日志里出现
Query_time: 1.234567,注意小数点后六位是微秒级精度,别误读成毫秒;实际耗时应看整个字段,不是只看整数部分 - 警惕
Lock_time接近Query_time的语句——说明不是 SQL 本身慢,而是锁等待严重,这时要结合SHOW ENGINE INNODB STATUS看事务阻塞链
EXPLAIN 结果里哪些字段一出现就该警觉
EXPLAIN 不是看有没有 type=ALL 就完事,很多性能问题藏在更细的字段组合里,比如 key 显示用了索引,但 rows 却高达百万,说明索引区分度极差。
-
type出现index_merge:MySQL 同时用了多个索引再合并结果,通常意味着单列索引设计不合理,应考虑联合索引 -
Extra里有Using filesort或Using temporary:基本等于“必然触发磁盘临时表或排序”,尤其是ORDER BY字段没走索引、或GROUP BY和SELECT字段不一致时高频出现 -
key_len比预期小(比如VARCHAR(255)字段只用了 2 字节):说明只用了索引最左前缀,可能是WHERE条件里没包含索引第一列,或用了函数/隐式类型转换导致索引失效
为什么 SET profiling=ON 查到的耗时和慢日志对不上
SET profiling=ON 是会话级功能,只记录当前连接的语句耗时,且 MySQL 5.7+ 默认禁用,8.0+ 已移除。它测的是“单次执行”的客户端视角耗时,不含网络延迟、连接池排队、锁等待等外部因素,所以数值往往比慢日志里记录的 Query_time 小得多。
- 替代方案:用
performance_schema查真实端到端耗时,例如:SELECT EVENT_NAME, TIMER_WAIT FROM performance_schema.events_statements_history_long WHERE SQL_TEXT LIKE '%SELECT%order%';
注意TIMER_WAIT单位是皮秒,要除以 1000000000 得到秒 - 线上环境慎用
performance_schema全量采集,开销不小;建议只对特定线程 ID(THREAD_ID)临时打开,用完立刻关 - 真正的“用户感知耗时”还得看应用层打点——数据库里 50ms 的 SQL,如果前端发了 12 次串行请求,总耗时就是 600ms,这类问题不会出现在任何数据库日志里
慢查询分析最麻烦的从来不是工具怎么用,而是分不清“SQL 执行慢”“锁住别人”“被别人锁住”“网络卡了”“应用反复重试”这几种情况——它们在日志里可能只差一行 Lock_time,但根因和解法天差地别。










