MySQL慢查询日志的实现与配置
MySQL慢查询日志完全指南:从入门配置到生产环境故障排查实战
在数据库性能调优领域,MySQL慢查询日志无疑是最核心的SQL性能诊断工具之一。无论你是刚入行的开发新手,还是需要在生产环境保障稳定的运维工程师,掌握慢查询日志都是必备技能。今天这篇文章,我们将全方位深入剖析慢查询日志——从基本原理、参数配置、生产环境最佳实践,到故障排查方法与面试高频考点,一次讲透。
先给出核心定义:慢查询日志是 MySQL 内置的 SQL 性能监控记录仪,专门用于自动捕获那些执行效率低、响应时间长的慢 SQL。当线上项目出现 CPU 飙升、API 接口超时、页面加载卡顿等状况时,首要排查步骤就是启用慢日志,快速定位问题 SQL。

重要提示:慢查询日志采用被动记录机制——它不会干预 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 |
阈值的设定也有讲究:
- 开发环境建议设为 0.1 秒,严格排查,提前发现隐患。极端场景甚至可以设为 0 秒,记录所有 SQL 用于全面分析。
- 线上环境建议设为 1~2 秒,只记录真正影响性能的慢 SQL。
进阶参数:生产环境推荐配置
| 参数 | 含义 | 推荐值 |
|---|---|---|
| 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 配置文件。
四、实战疑难问题全面解析
问题1:同样是全表扫描,为什么有些进入慢日志,有些没有?
核心规则再强调一遍:慢日志默认只关注耗时,不关心是否全表扫描。
你的 4000 行小表,全表扫描仅需 0.03 秒,远低于阈值,因此不被记录;等到数据量增长到 10 万行,全表扫描耗时暴涨超过阈值,就会立即被记录。
如果开启了 log_queries_not_using_indexes,无索引的 SQL 即使不超时也会被记录——但小表场景可以通过 min_examined_row_limit 参数进行过滤。
问题2:LIKE '王%' 前缀模糊查询,到底会不会进入慢日志?
答案完全取决于查询列上是否存在索引,不存在所谓的“隐性优化规则”。直接看对比表:
| 场景 | 执行方式 | 是否被记录 |
|---|---|---|
| 列有索引 + LIKE '王%' | 索引范围扫描(不是全表扫描) | 不触发无索引记录;超时才记录 |
| 列无索引 + LIKE '王%' | 全表扫描 | 开了无索引记录就记录,超时也记录 |
| LIKE '%王' 左模糊 | 无论有无索引,都无法走索引范围扫描 | 全表扫描,开了无索引记录就记录 |
记住这个关键对比:LIKE '王%' 在有索引时能够走索引范围扫描,不属于全表扫描;而 LIKE '%王' 这种左模糊查询,无法利用 B+ 树索引的有序性,必然走全表扫描。
问题3:为什么 xuesheng_yizizhu > 100 全表扫描会被记录?
这条 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 | 扫描行都是需要的,考虑业务需求是否合理 |
六、三种环境下的慢日志查看方法
本地 PHPStudy 环境
直接找到 slow.log 文件,用文本编辑器打开即可直观查看原始日志内容,适合本地开发和调试场景。
线上 Linux 服务器(企业常用)
生产环境中有两种主流的慢日志分析工具:
方法一: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
阿里云/火山RDS云数据库
如果没有服务器权限,直接在云控制台操作即可:实例详情 → 日志管理 → 慢查询日志,支持条件筛选、结果导出、一键分析等便捷功能。
七、日志自动切割方案:生产环境必备配置
线上慢日志会持续增长,如果不配置自动切割机制,单个日志文件过大可能会占满磁盘空间,引发次生故障。
方案一: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;"
八、开发环境与生产环境落地规范
开发环境规范
- 开启慢日志 + 设置低耗时阈值(0.1秒)+ 开启记录无索引 SQL
- 上线前清零所有全表扫描和慢查询 SQL,提前规避线上风险
- 极端排查场景可设 long_query_time=0,记录所有 SQL 用于全面分析
线上生产环境规范
- 慢日志总开关永久开启,严禁关闭
- 关闭无索引 SQL 记录,防止海量日志占满磁盘
- 配置 min_examined_row_limit,即使临时开启无索引记录也能过滤小表噪音
- 配置日志自动切割,避免单文件过大
- 避免无条件全表查询,避免左模糊/全模糊查询 %xxx,业务需要时用 ES 或搜索引擎替代
- 设置合理的 long_query_time(1~2秒),阈值太低日志爆炸,太高漏掉问题
九、企业标准 SQL 优化流程
接下来是一套标准打法:慢日志抓取问题 SQL → EXPLAIN 分析执行计划 → 补索引或改写 SQL → 复测性能。
这是业界通用的数据库性能排查流程,适用于绝大多数卡顿问题的定位与解决:
发现问题 → 慢日志抓SQL → EXPLAIN分析 → 优化方案 → 上线复测
↑ |
└────────────── 未解决则循环 ←───────────────────────┘
十、面试高频考点速记卡
| # | 核心要点 | 一句话记忆 |
|---|---|---|
| 1 | 慢日志记录条件 | 耗时超阈值 或 无索引(需开启),两者是"或"关系 |
| 2 | 线上核心规范 | 慢日志永久开启,关闭无索引记录,调高耗时阈值 |
| 3 | 全表扫描 ≠ 慢查询 | 小表全表扫描可能很快,不会触发耗时记录 |
| 4 | 模糊查询索引问题 | LIKE '王%' 有索引走范围扫描,LIKE '%王' 一定全表扫描 |
| 5 | 问题判断核心 | 扫描行数远大于返回行数 = 需要优化索引 |
| 6 | 优化固定流程 | 抓慢SQL → EXPLAIN分析 → 优化SQL/索引 → 复测 |
| 7 | 动态修改 | SET GLOBAL 可不停机修改,但 long_query_time 需新连接才生效 |
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
phpMyAdmin批量导入多个小型SQL碎片文件方法
许多开发者习惯将多个小型SQL碎片文件一同上传到phpMyAdmin的导入页面,误以为平台能像文件夹一样批量处理——但实际情况是,系统仅识别第一个文件,其余文件会被静默忽略,无法执行。 根本原因其实并不复杂:phpMyAdmin的导入机制本质上是一个单文件上传接口。其import页面仅包含一个字段,
phpMyAdmin设置表AUTO_INCREMENT起始值的方法
phpMyAdmin里改AUTO_INCREMENT值,点“保存”却没反应? 其实,问题往往出在两个容易被忽视的细节上: 1 **错误点击了“保存”而非“执行”按钮**。phpMyAdmin 的“操作”页面中,AUTO_INCREMENT 输入框属于一个独立的表单。如果在字段旁点击“保存”
MySQL主从数据一致性检查pt-table-checksum使用方法和步骤详解
pt-table-checksum 必须在主库执行——这一点,很多初次接触的人都会踩坑。它并不是“直连从库去比对”,而是借助 binlog 复制将校验逻辑同步过去,由从库本地重新计算,再写入 percona checksums 表。简单来说,你在主库发送一条类似 REPLACE INTO perco
MySQL连接被阻断错误原因及解除方法
你是否遇到过 MySQL 报出 Host is blocked 的错误?先别急着怀疑密码是否正确——这本质上并非单纯的连接失败,而是你的 IP 地址已被 MySQL 主动列入黑名单。此时,即便输入完全正确的密码,数据库也会毫不留情地拒绝访问。要想立刻解除封锁,唯一的办法就是清空 host cache
MySQL 8.0跨库联合查询权限配置详解
MySQL 8 0 的跨库联合查询功能原生内置,无需额外安装插件或修改配置文件。很多开发者遇到 SQL 语法正确却报 ERROR 1142 的情况时,常会困惑——其实并非 MySQL 限制跨库操作,而是权限验证环节未通过。 简而言之,跨库查询受阻的根源通常不是功能未启用,而是权限分配不完整或授权语句
- 日榜
- 周榜
- 月榜
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
1
2
3
4
5
6
7
8
9
10
相关攻略
2026-07-05 07:05
2026-07-05 07:04
2026-07-05 07:04
2026-07-05 07:04
2026-07-05 07:04
2026-07-05 07:04
2026-07-05 07:03
2026-07-05 07:03
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

