【Java 开发日记】我们来说一下 MySQL 的慢查询日志

【Java 开发日记】我们来说一下 MySQL 的慢查询日志

慢查询日志(Slow Query Log)是 MySQL 性能优化的最重要入口之一
它能帮你快速定位“拖慢整个系统”的 SQL,是排查线上卡顿、CPU/IO 高、连接堆积的第一把钥匙

今天我们从为什么用 → 怎么开 → 怎么配 → 怎么分析 → 生产注意事项 全流程走一遍(基于 MySQL 8.x / 5.7+,2025–2026 主流实践)。

1. 为什么一定要用慢查询日志?

  • 业务代码里看不到执行时间分布
  • EXPLAIN 只能单条分析,生产里成千上万条 SQL 不可能一条条 explain
  • 慢查询日志自动记录超过阈值的 SQL + 执行信息(耗时、扫描行数、锁时间等)
  • 结合 pt-query-digest / mysqldumpslow 一键聚合出 Top 慢 SQL

一句话:没有慢查询日志,你就是在盲人摸象调优

2. 核心参数一览(2025 推荐配置)

参数作用默认值生产推荐值(常见场景)说明
slow_query_log是否开启慢查询日志OFFON(临时开启 / 间歇采集)核心开关
slow_query_log_file日志文件路径主机名-slow.log/var/log/mysql/slow.log 或自定义确保目录 mysql 用户可写
long_query_time超过多少秒算慢(单位:秒,可小数)101~3(甚至 0.5~1)越小日志越多,建议从 2 开始调
log_queries_not_using_indexes未走索引的查询也记录(即使没超时间)OFFON(排查阶段开,生产慎开)非常有用,但会让日志暴增
log_output日志输出位置FILEFILE 或 TABLE(mysql.slow_log)FILE 更常见,TABLE 便于查询
min_examined_row_limit扫描行数少于此值的不记录01000 或 5000(过滤小表全扫)减少噪音
log_slow_admin_statements慢的管理语句(ALTER 等)也记录OFF根据需要一般不开

3. 怎么开启?(三种方式对比)

方式一:临时开启(推荐排查时用,重启失效)

-- 开启慢查询
SET GLOBAL slow_query_log = 1;

-- 设置阈值(建议从 2 秒开始,逐步降低)
SET GLOBAL long_query_time = 2;

-- 强烈建议:记录未走索引的查询(排查神器)
SET GLOBAL log_queries_not_using_indexes = 1;

-- 查看当前配置(立即生效)
SHOW VARIABLES LIKE '%slow_query%';
SHOW VARIABLES LIKE 'long_query_time';

方式二:永久开启(修改配置文件,推荐生产间歇采集)

/etc/my.cnf/etc/mysql/my.cnf(或容器里的对应路径)中添加:

[mysqld]
slow_query_log                  = 1
slow_query_log_file             = /var/log/mysql/slow.log
long_query_time                 = 2
log_queries_not_using_indexes   = 1                # 排查期开启,平时关闭
min_examined_row_limit          = 1000
log_output                      = FILE
# log_slow_admin_statements     = 1                # 可选

然后重启 MySQL(或容器重启)。

生产建议不要一直开,尤其是 log_queries_not_using_indexes=1 会导致日志文件快速膨胀。
推荐做法:平时关闭 → 问题出现时开启 1-2 小时采集 → 分析完关闭

方式三:输出到表(方便 SQL 查询)

SET GLOBAL log_output = 'TABLE';

慢 SQL 会写入 mysql.slow_log 表,可直接查询:

SELECT * FROM mysql.slow_log ORDER BY start_time DESC LIMIT 50;

4. 慢查询日志长什么样?(典型格式)

# Time: 2026-01-26T18:45:12.345678Z
# User@Host: app_user[app_user] @ 192.168.1.50 []
# Query_time: 4.567  Lock_time: 0.000123 Rows_sent: 1  Rows_examined: 8500000
# Rows_affected: 0
SET timestamp=1706291112;
SELECT * FROM orders 
WHERE status = 'pending' 
  AND created_at > '2025-12-01' 
ORDER BY id DESC LIMIT 10;

关键字段:

  • Query_time:实际执行时间(最重要)
  • Lock_time:等待行锁 / 表锁 时间
  • Rows_examined:扫描了多少行(越大越可疑)
  • Rows_sent:返回多少行

5. 怎么分析慢查询日志?(生产常用工具)

工具 1:官方 mysqldumpslow(最轻量)

# 汇总前 10 条最慢的(自动按总耗时排序)
mysqldumpslow -s t -t 10 /var/log/mysql/slow.log

# 按扫描行数排序
mysqldumpslow -s r -t 10 /var/log/mysql/slow.log

# 只看某个用户的
mysqldumpslow -s t -t 10 -u app_user /var/log/mysql/slow.log

输出示例:

Count: 128  Time=5.2s (665s)  Lock=0.00s (0s)  Rows=1 (128), app_user[app_user]@192.168.1.%
  SELECT * FROM orders WHERE status = ? AND created_at > ?

工具 2:pt-query-digest(Percona 工具,推荐!)

pt-query-digest /var/log/mysql/slow.log > digest.txt

它会给你:

  • 按照执行次数、总耗时、平均耗时、95% 耗时 等多种维度排名
  • 自动合并参数化后的相同 SQL
  • 显示执行计划摘要

生产必备:几乎所有 DBA 都用这个。

6. 生产最佳实践 & 注意事项(2025–2026 版)

  1. 阈值设置:线上从 1~3 秒开始,逐步调到业务能接受的 95 分位线(用监控看)。
  2. 不要常开:开启会增加少量 IO 和 CPU 开销,尤其是 log_queries_not_using_indexes=1
  3. 日志轮转:用 logrotate 每天/每周轮转,避免单文件过大。
   /var/log/mysql/slow.log {
       daily
       rotate 7
       compress
       missingok
       create 640 mysql mysql
   }
  1. 结合监控:Prometheus + mysqld_exporter 监控 slow_queries 指标,超过阈值告警。
  2. 下一步动作:找到 Top 慢 SQL 后,立刻 EXPLAIN ANALYZE(MySQL 8.0+)或 EXPLAIN FORMAT=JSON
  3. 常见优化方向
  • 加/改索引(联合索引、覆盖索引)
  • 避免 SELECT *函数(列)OR!=LIKE '%xx%'
  • 大表分页用延迟关联
  • 拆分复杂 JOIN

小结 & 下一步想聊什么?

慢查询日志是 “发现问题” 的神器,接下来才是真正的优化战场(索引、SQL 重写、分库分表、读写分离…)。

你现在最想深入哪个部分?
A. pt-query-digest 的详细用法 + 真实案例解析
B. 结合 EXPLAIN ANALYZE 如何读懂执行计划
C. 线上如何安全“限时开启”慢查询(不重启、不影响业务)
D. 慢 SQL 优化实战:从日志到加索引 / 重写 SQL 的完整流程
E. Percona Toolkit 全家桶简介(pt-query-digest / pt-index-usage 等)

告诉我字母,继续写!

文章已创建 4138

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部