MySQL慢查询日志:从入门到线上排障,这一篇就够了 要说数据库调优里最常用的工具,慢查询日志绝对是排得上号的。无论你是刚入门的开发,还是需要在生产环境扛雷的运维,都绕不开它。今天这篇文章,咱们就把慢查询日志掰开揉碎了讲清楚——它是什么、怎么配、上线怎么用、遇到问题怎么看,以及那些面试官最爱挖坑的细
要说数据库调优里最常用的工具,慢查询日志绝对是排得上号的。无论你是刚入门的开发,还是需要在生产环境扛雷的运维,都绕不开它。今天这篇文章,咱们就把慢查询日志掰开揉碎了讲清楚——它是什么、怎么配、上线怎么用、遇到问题怎么看,以及那些面试官最爱挖坑的细节到底是怎么回事。
我先抛个核心判断:慢查询日志是 MySQL 的 SQL 性能记录仪,专门自动记录那些执行慢、性能差的 SQL。线上项目 CPU 飙升了?接口超时了?页面加载变慢了?别慌,第一件事就是打开慢日志,找到问题 SQL。
长期稳定更新的攒劲资源: >>>点此立即查看<<<

注意:它是被动记录的——它不会阻止 SQL 的执行,也不会影响业务的正常运行。慢日志只是“记录”,不是“拦截”。
对于运维和开发来说,这个工具的定位很简单:问题排查的第一把钥匙。线上出了故障,没有慢日志,就等于没有线索。
别看网上各种说法满天飞,其实默认的记录条件只有一个:执行时间超过 long_query_time 这个阈值。
那个 log_queries_not_using_indexes 参数,是额外的附加开关。把它打开后,即使 SQL 执行时间没超过阈值,但只要没用索引(走全表扫描),也会被记录下来。
这两个条件是什么关系?简单说,“或”的关系——满足任何一个,就会被记录:
| 条件 | 是否记录 |
|---|---|
| 执行时间 > 阈值 | 记录 |
| 执行时间 ≤ 阈值,但无索引 + 开启了无索引记录 | 记录 |
| 执行时间 ≤ 阈值,且无索引记录未开启 | 不记录 |
这里有个关键认知必须建立起来:全表扫描 ≠ 慢查询。一张 4000 行的小表,全表扫描可能只要 0.01 秒,远低于阈值,自然不会触发慢日志(除非你专门开启无索引记录)。
这是一道经典的面试题,也是很多新手容易漏掉的地方。直接说结论:线上慢日志总开关必须永久开启,绝对不能关闭!
有些同学担心开启慢日志会占用性能。其实完全多虑了:慢日志的写入是追加式 IO,对整体性能影响极小(通常 < 1%)。真正影响性能的,是那些问题 SQL 本身,而不是记录问题 SQL 的日志。
关闭慢日志的后果是什么?线上出故障时没有日志可查,你连问题 SQL 都找不到,更别提定位根源了。所以,线上正确的做法是:开关不关,只调优参数——调高耗时阈值、关闭无索引 SQL 记录,防止日志爆炸。
要查看所有慢日志参数,直接执行 SHOW VARIABLES LIKE 'slow_query%'; 就行。下面这三项是必配的:
| 参数 | 含义 | 推荐值 |
|---|---|---|
| slow_query_log | 慢日志总开关 | 线上永久 ON |
| long_query_time | 慢查询判定阈值(单位:秒) | 开发:0.1秒 / 线上:1~2秒 |
| log_queries_not_using_indexes | 是否记录无索引全表扫描SQL | 开发:ON / 线上:OFF |
阈值的设定也有讲究:
| 参数 | 含义 | 推荐值 |
|---|---|---|
| slow_query_log_file | 日志文件存储路径 | 确保有磁盘空间,路径可访问 |
| min_examined_row_limit | 最少扫描行数阈值 | 100~1000,过滤小表噪音 |
| log_output | 日志输出方式 | FILE(默认)/ TABLE |
这个 min_examined_row_limit 配合无索引记录使用效果特别好:即使开了 log_queries_not_using_indexes,扫描行数低于这个值的 SQL 也不会被记录,可以大幅减少小表产生的无效日志。
线上不想重启 MySQL 时,直接用动态命令即可:
-- 临时开启慢日志(重启后失效)
SET GLOBAL slow_query_log = ON;
-- 临时调整阈值
SET GLOBAL long_query_time = 2;
不过要注意:long_query_time 修改后,需要新连接才生效,已有连接仍然使用旧值。要永久生效,还得同时改 my.cnf 配置文件。
核心规则再强调一遍:慢日志默认只看耗时,不看是否全表扫描。
你的 4000 行小表,全表扫描只需 0.03 秒,低于阈值,所以不记录;等到数据量超过 10 万行,全表扫描耗时暴涨超过阈值,立刻被记录。
如果开了 log_queries_not_using_indexes,无索引 SQL 即使不超时也会被记录——但小表可以用 min_examined_row_limit 过滤掉。
答案完全取决于列上是否有索引,不存在什么“隐性优化规则”。直接看表:
| 场景 | 执行方式 | 是否被记录 |
|---|---|---|
| 列有索引 + LIKE '王%' | 索引范围扫描(不是全表扫描) | 不触发无索引记录;超时才记录 |
| 列无索引 + LIKE '王%' | 全表扫描 | 开了无索引记录就记录,超时也记录 |
| LIKE '%王' 左模糊 | 无论有无索引,都无法走索引范围扫描 | 全表扫描,开了无索引记录就记录 |
记住这个对比:LIKE '王%' 在有索引时能走范围扫描,不是全表扫描;而 LIKE '%王' 这种左模糊,无法利用 B+ 树索引的有序性,一定全表扫描。
这条 SQL 扫描全表 4400 行、返回 4300+ 行,被记录有两个可能原因:
log_queries_not_using_indexes:没有索引,直接满足无索引记录条件,跟扫描行数多少无关。long_query_time 阈值。判断:扫描行数远大于返回行数,这是索引缺失的信号。但注意,这不是慢日志记录的原因,而是需要优化的原因。
拿到慢日志,不用看杂乱的内容,只看这 4 个字段就能定位问题:
| 字段 | 含义 | 问题判断 |
|---|---|---|
| Query_time | SQL总执行耗时 | 核心依据,数值大 = SQL本身慢 |
| Lock_time | 锁等待耗时 | 数值高是锁竞争问题 |
| Rows_examined | 实际扫描行数 | 风险核心,数值大 = 可能在全表扫描 |
| Rows_sent | 最终返回的行数 | 用于和扫描行数对比 |
记住一个万能判断口诀:Rows_examined Rows_sent(扫描行数远大于返回行数)= 索引缺失或索引失效,必须优化。
几个典型场景速判:
| 现象 | 诊断 |
|---|---|
| Query_time大,Lock_time小 | SQL本身慢,需要优化索引或改写SQL |
| Query_time大,Lock_time大 | 锁竞争严重,需要优化事务/锁粒度 |
| Rows_examined >> Rows_sent | 索引缺失或失效,补索引或改写SQL |
| Rows_examined ≈ Rows_sent | 扫描行都是需要的,考虑业务需求是否合理 |
直接找到 slow.log 文件,用编辑器打开,直观查看原始日志,适合本地调试。
线上环境有两种主流分析工具:
方法一:mysqldumpslow(MySQL 自带,简单快捷)
它能自动合并重复 SQL、排序统计,解决日志杂乱的问题。常用命令:
# 查耗时最长Top10
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log
# 查执行次数最多Top10
mysqldumpslow -s c -t 10 /var/log/mysql/slow.log
# 查平均耗时最长Top10
mysqldumpslow -s at -t 10 /var/log/mysql/slow.log
注意:mysqldumpslow 只能分析 FILE 格式的日志。如果 log_output=TABLE,就需要用 SELECT * FROM mysql.slow_log 来查询。
方法二:pt-query-digest(Percona Toolkit,企业主流)
这个工具比 mysqldumpslow 强大得多,是实际运维中最常用的:
# 分析慢日志,输出完整报告
pt-query-digest /var/log/mysql/slow.log
# 只分析最近1小时的慢查询
pt-query-digest --since '1h' /var/log/mysql/slow.log
# 将结果保存到数据库
pt-query-digest --review h=host,D=db,t=review /var/log/mysql/slow.log
没有服务器权限,直接在控制台操作:实例详情 → 日志管理 → 慢查询日志,支持筛选、导出、一键分析。
线上慢日志会持续增长,如果不配置自动切割,单文件过大可能会占满磁盘。
方案一:logrotate(Linux 系统自带)
创建配置文件 /etc/logrotate.d/mysql-slow:
/var/log/mysql/slow.log {
daily
rotate 30
missingok
compress
delaycompress
notifempty
create 640 mysql mysql
postrotate
mysql -e "SELECT 1" >/dev/null 2>&1 || true
endscript
}
方案二:手动 mv + flush(简单直接)
# 1. 重命名当前日志
mv /var/log/mysql/slow.log /var/log/mysql/slow.log.bak
# 2. 刷新MySQL日志句柄(MySQL自动创建新文件)
mysql -e "FLUSH SLOW LOGS;"
接下来就是一套标准打法了:慢日志抓取问题 SQL → EXPLAIN 分析执行计划 → 补索引/改写 SQL → 复测性能。
这是业界通用的数据库性能排查流程,适用于绝大多数卡顿问题的定位和解决:
发现问题 → 慢日志抓SQL → EXPLAIN分析 → 优化方案 → 上线复测
↑ |
└────────────── 未解决则循环 ←───────────────────────┘
| # | 核心要点 | 一句话记忆 |
|---|---|---|
| 1 | 慢日志记录条件 | 耗时超阈值 或 无索引(需开启),两者是"或"关系 |
| 2 | 线上核心规范 | 慢日志永久开启,关闭无索引记录,调高耗时阈值 |
| 3 | 全表扫描 ≠ 慢查询 | 小表全表扫描可能很快,不会触发耗时记录 |
| 4 | 模糊查询索引问题 | LIKE '王%' 有索引走范围扫描,LIKE '%王' 一定全表扫描 |
| 5 | 问题判断核心 | 扫描行数远大于返回行数 = 需要优化索引 |
| 6 | 优化固定流程 | 抓慢SQL → EXPLAIN分析 → 优化SQL/索引 → 复测 |
| 7 | 动态修改 | SET GLOBAL 可不停机修改,但 long_query_time 需新连接才生效 |
侠游戏发布此文仅为了传递信息,不代表侠游戏网站认同其观点或证实其描述