2、MySQL慢查询基础:慢查询日志的开启与配置、慢查询日志的格式解读、使用mysqldumpslow分析日志

在Go项目连接池调优之前,必须先建立慢查询监控能力。MySQL慢查询日志是定位低效SQL最直接的工具,它记录了执行时间超过指定阈值的所有SQL语句。本章将系统讲解慢查询日志的开启配置、日志格式解析以及使用官方工具mysqldumpslow进行聚合分析的方法。

2.1 慢查询日志的开启与配置

MySQL默认关闭慢查询日志,需要手动启用。推荐在my.cnf配置文件中进行持久化设置,避免重启后失效。

2.1.1 核心配置参数

参数名 默认值 说明
slow_query_log OFF 是否开启慢查询日志,设为1或ON开启
slow_query_log_file hostname-slow.log 慢查询日志文件路径,建议指定绝对路径
long_query_time 10.000000 SQL执行时间超过此值(秒)才记录,生产环境建议设为1或0.5
log_queries_not_using_indexes OFF 是否记录未使用索引的查询,调优时建议开启
log_slow_admin_statements OFF 是否记录慢管理语句(如ALTER TABLE、ANALYZE TABLE)
min_examined_row_limit 0 扫描行数超过此值才记录,可用于过滤小表全表扫描

2.1.2 配置文件示例

在my.cnf的[mysqld]段添加以下配置:

[mysqld]
# 开启慢查询日志
slow_query_log = 1
# 日志文件路径,确保MySQL用户有写入权限
slow_query_log_file = /var/log/mysql/mysql-slow.log
# 阈值:超过1秒即记录
long_query_time = 1
# 记录未使用索引的查询
log_queries_not_using_indexes = 1
# 记录慢管理语句
log_slow_admin_statements = 1
# 扫描行数超过1000行才记录(可选过滤)
min_examined_row_limit = 1000
生产建议:在Docker容器中运行MySQL时,建议将慢查询日志挂载到宿主机目录,便于集中采集和分析。同时注意日志文件可能快速增长,建议配置日志轮转(如logrotate)或定期清理。

2.1.3 运行时动态修改

无需重启MySQL,可通过SET GLOBAL命令在线调整:

-- 开启慢查询日志
SET GLOBAL slow_query_log = ON;

-- 设置阈值1秒
SET GLOBAL long_query_time = 1;

-- 查看当前配置
SHOW VARIABLES LIKE 'slow_query_log%';
SHOW VARIABLES LIKE 'long_query_time';
注意:long_query_time的修改仅对新连接生效,已存在的连接仍使用旧值。建议在修改后重新建立数据库连接,或通过连接池刷新连接。

2.2 慢查询日志的格式解读

理解慢查询日志的每一行含义,是精准定位性能瓶颈的前提。以下是一条典型的慢查询日志记录:

# Time: 2025-03-15T10:23:45.123456Z
# User@Host: go_app[go_app] @  [172.17.0.3]  Id:  12345
# Query_time: 2.345678  Lock_time: 0.000123  Rows_sent: 50  Rows_examined: 50000
# Thread_id: 12345  Schema: ecommerce  Last_errno: 0  Killed: 0
# Query_time distribution:
#   1% in 0.1s to 0.5s
#  99% in 2.0s to 5.0s
SET timestamp=1742027025;
SELECT o.id, o.total_amount, u.name
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 'pending'
ORDER BY o.created_at DESC
LIMIT 50;

2.2.1 日志字段解析

字段 示例值 含义
Time 2025-03-15T10:23:45.123456Z SQL执行结束的时间戳(UTC)
User@Host go_app[go_app] @ [172.17.0.3] 执行SQL的用户名、主机名和客户端IP
Query_time 2.345678 SQL实际执行时间(秒),核心关注指标
Lock_time 0.000123 等待表锁或行锁的时间(秒)
Rows_sent 50 返回给客户端的行数
Rows_examined 50000 MySQL为执行查询扫描的行数
Thread_id 12345 执行该SQL的线程ID
Schema ecommerce 当前使用的数据库名
SET timestamp 1742027025 SQL执行开始时间的Unix时间戳
关键指标解读:
  • Query_time:直接反映SQL性能,超过long_query_time阈值即被记录。
  • Rows_examined / Rows_sent:比值过大(如1000:1)通常表示缺少索引或查询条件不精确。
  • Lock_time:过高可能暗示锁竞争,需要检查事务隔离级别或并发写操作。

2.3 使用mysqldumpslow分析日志

原始慢查询日志包含大量重复SQL(仅参数不同),手动分析效率极低。mysqldumpslow是MySQL官方提供的日志聚合工具,能将相似的SQL归并统计,输出排名靠前的“慢查询模式”。

2.3.1 基本语法

mysqldumpslow [options] [log_file ...]

2.3.2 常用选项

选项 说明 示例
-s 排序方式:t(按查询时间)、c(按计数)、l(按锁时间)、r(按返回行数) -s t
-t 只显示前N条 -t 10
-g 正则过滤SQL内容 -g "SELECT.*orders"
-a 不将数字抽象为N,显示原始值 -a
--verbose 详细输出 --verbose

2.3.3 典型使用场景

场景1:查看耗时最长的前5条SQL

mysqldumpslow -s t -t 5 /var/log/mysql/mysql-slow.log

场景2:查看出现次数最多的前10条SQL

mysqldumpslow -s c -t 10 /var/log/mysql/mysql-slow.log

场景3:过滤出涉及orders表的慢查询

mysqldumpslow -g "orders" /var/log/mysql/mysql-slow.log

2.3.4 输出示例解读

Count: 123  Time=2.34s (288s)  Lock=0.00s (0s)  Rows=50.0 (6150), go_app[go_app]@[172.17.0.3]
  SELECT o.id, o.total_amount, u.name
  FROM orders o
  JOIN users u ON o.user_id = u.id
  WHERE o.status = 'N'
  ORDER BY o.created_at DESC
  LIMIT N
聚合字段 值 含义
Count 123 该模式SQL共执行了123次
Time=2.34s (288s) 平均2.34秒,总耗时288秒 平均执行时间 / 括号内为累计总时间
Lock=0.00s (0s) 平均锁等待0秒 锁竞争不严重
Rows=50.0 (6150) 平均返回50行,累计返回6150行 每次返回行数稳定
分析技巧:优先关注Count高且Time大的SQL,它们对系统总负载影响最大。如果Rows_examined远大于Rows_sent,应检查索引是否缺失或查询条件是否需要优化。

2.4 慢查询日志分析流程(SVG)

下图展示了从开启日志到定位慢SQL的完整工作流:

慢查询日志分析流程 开启慢查询日志 配置 long_query_time 与日志路径 Go应用运行 → 产生慢查询日志 mysqldumpslow 聚合分析 定位TOP慢SQL与模式 输出优化建议(索引/改写SQL)

2.5 慢查询日志与连接池性能的关系

在Go项目中,慢查询会直接影响连接池的行为:

  • 连接占用时间变长:一条慢查询执行2秒,意味着该连接在这2秒内无法被其他请求复用,导致连接池有效连接数减少。
  • 连接池排队加剧:当慢查询比例升高,连接池中的连接被长时间占用,新请求必须等待空闲连接,造成请求排队和超时。
  • 连接池扩容误判:如果监控系统看到连接池使用率上升,可能触发扩容策略,但实际是慢查询导致连接周转变慢,而非流量增长。
调优原则:在调整连接池参数(如MaxOpenConns、MaxIdleConns)之前,必须先通过慢查询日志消除或减少慢SQL。否则,连接池调优只能缓解症状,无法根治性能问题。

2.6 本章小结

  • 慢查询日志是MySQL性能调优的第一道防线,必须正确开启和配置。
  • 日志中的Query_time、Rows_examined、Rows_sent是核心分析指标。
  • mysqldumpslow工具能快速聚合日志,输出排名靠前的慢查询模式。
  • 慢查询与连接池性能强相关:慢SQL会降低连接复用率,加剧连接池竞争。