3. 慢查询日志格式解析:时间戳、用户、主机、查询耗时、锁等待时间、返回行数、扫描行数等字段含义

慢查询日志(Slow Query Log)是 MySQL 提供的核心诊断工具,记录了执行时间超过预设阈值(long_query_time)的 SQL 语句。在搜索服务压测场景中,尾延迟波动往往由少数“慢查询”引发,因此准确解析日志每一字段是定位根因的第一步。

以下以 MySQL 8.0 默认慢查询日志格式为例,逐字段拆解其含义与压测关联。

3.1 日志行结构总览

一条完整的慢查询日志记录由头信息行与SQL 语句行组成。头信息行包含执行上下文与耗时指标,SQL 行记录具体查询文本。

典型日志片段(已脱敏):
# Time: 2025-03-21T14:23:45.123456Z
# User@Host: search_user[search_app] @  [10.0.1.105]  Id: 98765
# Query_time: 2.345678  Lock_time: 0.001234  Rows_sent: 50  Rows_examined: 120000
# Thread_id: 98765  Schema: search_db  Last_errno: 0  Killed: 0
SET timestamp=1742567025;
SELECT /*+ NO_ICP */ item_id, title, price FROM items WHERE MATCH(title) AGAINST('蓝牙耳机') ORDER BY score DESC LIMIT 50;

3.2 字段含义详解

字段名 日志示例 含义 压测关联
Time 2025-03-21T14:23:45.123456Z 语句执行结束的 UTC 时间戳,精确到微秒 用于对齐压测时间线,判断慢查询是否集中在高负载时段
User@Host search_user[search_app] @ [10.0.1.105] 连接用户、应用名与客户端 IP 区分流量来源,识别是搜索服务节点还是后台任务触发的慢查询
Query_time 2.345678 查询实际执行耗时(秒),不含网络往返 尾延迟核心指标:超过 1s 的查询直接贡献 P99 延迟
Lock_time 0.001234 表锁或行锁等待时间(秒) 高锁等待暗示并发冲突,可能因热点行更新或 DDL 阻塞
Rows_sent 50 实际返回给客户端的行数 搜索分页场景下通常较小,若异常增大需检查分页逻辑
Rows_examined 120000 服务器扫描的行数(含存储引擎层) 扫描行数远大于返回行数 → 索引缺失或查询计划低效
Thread_id 98765 执行该查询的 MySQL 线程 ID 关联 SHOW PROCESSLIST 或 performance_schema 做深度追踪
Schema search_db 查询所在的数据库名 多租户场景下区分业务线
SET timestamp 1742567025 Unix 时间戳,用于 pt-query-digest 等工具重放 压测回放时保证时间顺序正确

3.3 关键字段的压测诊断价值

  • Query_time vs Lock_time:若 Lock_time 占比超过 30%,优先排查锁竞争;否则优先排查索引与扫描行数。
  • Rows_examined / Rows_sent 比值:比值 > 1000 时,通常意味着全表扫描或索引选择性差,是尾延迟的主要成因。
  • Time 字段的微秒精度:可精确判断慢查询是否集中在压测波峰后的 100ms 窗口内,辅助定位“雪崩”效应。
实战建议:在压测脚本中同时采集 SHOW GLOBAL STATUS LIKE 'Slow_queries',与慢查询日志条目数交叉验证,避免日志轮转导致漏记。

3.4 慢查询日志字段关系图

下图展示了一条慢查询记录中各字段如何协同反映查询性能瓶颈:

慢查询日志字段关系与诊断链路 # Time: 2025-03-21T14:23:45.123456Z # User@Host: search_user[search_app] @ [10.0.1.105] # Query_time: 2.345678 Lock_time: 0.001234 Rows_sent: 50 Rows_examined: 120000 # Thread_id: 98765 Schema: search_db SET timestamp=1742567025; SELECT ... FROM items WHERE MATCH(title) AGAINST('蓝牙耳机') ... 时间上下文 Time / SET timestamp 耗时指标 Query_time / Lock_time 扫描效率 Rows_examined / Rows_sent 身份 User / Host / Thread_id 诊断结论推导 • Query_time 2.35s → 超过搜索服务 P99 目标(500ms),直接贡献尾延迟 • Rows_examined(120000) / Rows_sent(50) = 2400 → 扫描效率极低,索引缺失或查询计划错误 • Lock_time 仅 1.2ms → 锁竞争非主因,优先优化索引 • User@Host 来自搜索应用节点 10.0.1.105 → 确认是线上流量,非后台任务

3.5 字段解析常见陷阱

注意以下易混淆点:
  • Query_time 不包含网络传输时间:客户端感知的延迟 = Query_time + 网络 RTT + 应用层处理时间。压测中若客户端延迟远大于 Query_time,需排查网络或连接池。
  • Lock_time 仅统计 MySQL 层锁等待:不包含存储引擎内部锁(如 InnoDB 行锁)。行锁等待时间需从 INNODB_TRX 或 performance_schema 获取。
  • Rows_examined 可能被存储引擎缓存影响:InnoDB buffer pool 命中时,实际物理 IO 可能远小于扫描行数,但扫描行数仍反映索引选择效率。
  • SET timestamp 与 Time 字段可能不一致:Time 是语句结束时间,SET timestamp 是语句开始时间。长查询两者差异可达 Query_time 值。

3.6 字段提取与格式化示例

使用 pt-query-digest 或自建脚本解析时,建议按以下结构提取字段:

# 使用 awk 提取关键字段(适用于 MySQL 8.0 默认格式)
awk '/^# Time:/ { time=$3 " " $4 }
     /^# User@Host:/ { user=$3; host=$5 }
     /^# Query_time:/ { qtime=$3; ltime=$5; rsent=$7; rexam=$9 }
     /^SELECT|^INSERT|^UPDATE|^DELETE/ {
       print time, user, host, qtime, ltime, rsent, rexam, $0
     }' slow-query.log
字段映射到压测指标:
  • Query_time → 服务端处理延迟(server_latency)
  • Rows_examined / Rows_sent → 索引效率比(efficiency_ratio)
  • Lock_time → 锁竞争系数(lock_contention)
  • Time → 压测时间轴对齐(timestamp_aligned)
将这些字段写入压测报告,可直接关联尾延迟波动与慢查询特征。