MySQL慢查询日志的实现
一、慢查询日志是什么?
慢查询日志就是 MySQL 的SQL性能记录仪,专门自动记录数据库里执行卡顿、性能差的SQL。
⚠️ 注意:慢日志只是被动记录,不会阻止SQL执行,不影响业务运行。
作用:线上项目CPU飙升、接口超时、页面加载慢,第一时间靠慢日志找到问题SQL,是运维和开发必备排障工具。
慢日志的记录机制(核心逻辑,必须理解)
慢日志的默认记录条件只有一个:执行时间 > long_query_time 阈值。
log_queries_not_using_indexes 是额外的附加开关,开启后,无索引的SQL即使不超时也会被记录。
两者是**"或"**的关系——满足任一条件即被记录:
| 条件 | 是否记录 |
|---|---|
| 执行时间 > 阈值 | ✅ 记录 |
| 执行时间 ≤ 阈值,但无索引 + 开启了无索引记录 | ✅ 记录 |
| 执行时间 ≤ 阈值,且无索引记录未开启 | ❌ 不记录 |
所以:全表扫描 ≠ 慢查询。小表全表扫描可能只需0.01秒,低于阈值就不会被记录(除非开了无索引记录)。
二、新手最大误区:线上慢日志要不要关闭?(面试必考)
核心结论:线上慢日志总开关必须永久开启,绝对不能关闭!
小白误区纠正
很多人觉得开慢日志占用性能,其实完全不用担心:
- 慢日志的写入是追加式IO,对性能影响极小(通常 < 1%)
- 真正影响性能的是问题SQL本身,不是记录问题SQL的日志
真实规范
关闭慢日志是重大隐患——线上出故障时无日志可排查,无法定位问题根源。
线上正确做法
不关闭开关,只调优参数:调高耗时阈值、关闭无索引SQL记录,避免日志爆炸。
三、核心配置参数(零基础必懂)
查询所有慢日志参数命令:SHOW VARIABLES LIKE 'slow_query%';
3.1 三大必备参数
| 参数 | 含义 | 推荐值 |
|---|---|---|
| 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)
3.2 进阶参数(线上必配)
| 参数 | 含义 | 推荐值 |
|---|---|---|
| slow_query_log_file | 日志文件存储路径 | 确保有磁盘空间,路径可访问 |
| min_examined_row_limit | 最少扫描行数阈值 | 100~1000,过滤小表噪音 |
| log_output | 日志输出方式 | FILE(默认)/ TABLE |
min_examined_row_limit 配合无索引记录使用:即使开了 log_queries_not_using_indexes,扫描行数低于此值的SQL也不会被记录,有效减少小表无效日志。
3.3 动态修改参数(不停机生效)
线上不想重启MySQL时,可以用动态命令:
-- 临时开启慢日志(重启后失效) SET GLOBAL slow_query_log = ON; -- 临时调整阈值 SET GLOBAL long_query_time = 2; -- 永久生效需同时修改 my.cnf 配置文件
⚠️ long_query_time 修改后,需要新连接才生效,已有连接仍用旧值。
四、实操疑难问题全解
问题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 | 锁等待耗时 | 数值高是锁竞争问题,不是SQL本身慢 |
| 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 | 扫描行都是需要的,考虑是否业务需求合理 |
六、三种环境查看慢日志的方法(全覆盖)
6.1 本地PHPStudy环境
直接找到 slow.log 文件,用编辑器打开,直观查看原始日志,适合本地调试。
6.2 线上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
6.3 阿里云/火山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重新打开日志文件
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 需新连接才生效 |
到此这篇关于MySQL慢查询日志的实现的文章就介绍到这了,更多相关MySQL慢查询日志内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
MySQL 优化利器 SHOW PROFILE 的实现原理及细节展示
这篇文章主要介绍了MySQL优化利器SHOW PROFILE的实现原理,通过实例代码展示SHOW PROFILE的用法,需要的朋友可以参考下2024-12-12


最新评论