MySQL Performance Schema 按线程聚合等待事件
来源:17golang原创
时间:2026-10-31 23:26:59 306浏览 收藏
排查 MySQL 等待变慢时,单看全局等待事件只能知道“哪类事件累计得多”,很难回答“是哪条连接贡献的”。更实用的入口是 performance_schema.events_waits_summary_by_thread_by_event_name:它按 THREAD_ID 和 EVENT_NAME 聚合,再与 performance_schema.threads 关联,就能把内部线程映射到连接 ID、用户和主机。
官方地址:https://dev.mysql.com/doc/refman/8.4/en/
最小排查链路是:先确认等待采集已开启,再查询线程汇总表,按SUM_TIMER_WAIT排序,并通过PROCESSLIST_ID区分前台连接;计时字段是 Performance Schema 的皮秒表示,不能直接当作秒读取。
先看懂按线程汇总表记录了什么
MySQL 8.4 把等待事件分成 current、history 和 summary 等不同表。本文使用的汇总表每行代表一个线程和一个事件名组合,核心字段如下:
| 字段 | 含义 | 排查用途 |
|---|---|---|
THREAD_ID | Performance Schema 内部线程标识 | 关联 threads,不要直接当连接 ID |
EVENT_NAME | 等待 instrument 名称 | 区分文件、同步、表 IO 等等待类别 |
COUNT_STAR | 汇总事件次数 | 判断频繁等待 |
SUM_TIMER_WAIT | 已计时等待的累计时长 | 排序寻找累计影响较大的线程 |
AVG_TIMER_WAIT | 已计时等待的平均时长 | 区分高频短等待和低频长等待 |
官方手册说明,计时值在读取时以皮秒展示,所以查询时应换算成秒或微秒。没有计时的 instrument,其计时列可能为 NULL;不要把这类空值解释为“没有等待”。

采集项没有打开时,为什么查询不到有用数据
Performance Schema 的等待采集受 instrument 和 consumer 两层配置影响。先用查询确认当前状态,再只打开需要观察的等待类别,避免把所有 instrument 无差别扩大到生产环境。
-- 先确认线程采集、当前等待消费者和目标 instrument 的状态
SELECT NAME, ENABLED
FROM performance_schema.setup_consumers
WHERE NAME IN ('global_instrumentation', 'thread_instrumentation', 'events_waits_current');
-- 只检查 IO 等待 instrument;实际名称应以本机查询结果为准
SELECT NAME, ENABLED, TIMED
FROM performance_schema.setup_instruments
WHERE NAME LIKE 'wait/io/%'
ORDER BY NAME
LIMIT 30;
-- 示例:仅为排查窗口打开线程级等待和计时;结束后按原状态恢复
UPDATE performance_schema.setup_consumers
SET ENABLED = 'YES'
WHERE NAME IN ('global_instrumentation', 'thread_instrumentation', 'events_waits_current');
UPDATE performance_schema.setup_instruments
SET ENABLED = 'YES', TIMED = 'YES'
WHERE NAME LIKE 'wait/io/%';
这段配置只说明调整方向,不能替代现场权限和负载评估。若目标是历史等待,还要检查对应的 events_waits_history 或 events_waits_history_long consumer;如果只想读取汇总结果,应先确认目标 instrument 已启用并计时。
把 THREAD_ID 映射到具体连接,再按累计等待排序
真正定位连接时,不要把 THREAD_ID 和 PROCESSLIST_ID 混用。threads 表中的 PROCESSLIST_ID 对前台线程对应连接标识;后台线程通常没有可供用户终止的连接 ID。下面的查询只保留前台连接,并把皮秒转换成秒:
-- 只看前台连接,按累计等待从高到低列出排查候选
SELECT
s.THREAD_ID,
t.PROCESSLIST_ID AS connection_id,
t.PROCESSLIST_USER AS user_name,
t.PROCESSLIST_HOST AS client_host,
s.EVENT_NAME,
s.COUNT_STAR,
ROUND(s.SUM_TIMER_WAIT / 1000000000000, 6) AS sum_wait_seconds,
ROUND(s.AVG_TIMER_WAIT / 1000000000000, 6) AS avg_wait_seconds
FROM performance_schema.events_waits_summary_by_thread_by_event_name AS s
JOIN performance_schema.threads AS t
ON t.THREAD_ID = s.THREAD_ID
WHERE t.TYPE = 'FOREGROUND'
AND t.PROCESSLIST_ID IS NOT NULL
AND s.COUNT_STAR > 0
ORDER BY s.SUM_TIMER_WAIT DESC
LIMIT 20;
结果中的 connection_id 可与进程列表中的连接 ID 对照,EVENT_NAME 再决定下一步是看文件 IO、同步对象、表 IO 还是其他 instrument。这里的排序是“累计等待”的排序,不等于当前仍在等待,也不能单独证明某条 SQL 一定是根因。

用时间窗口清零,避免把旧累计量当成新故障
汇总表会持续累计,适合看窗口内的趋势,但不适合直接代表“刚刚发生的故障”。开始一次排查前,可以记录当前值;需要完全重开窗口时,按官方允许的方式清零汇总表,然后等待一个固定观察周期再查询:
-- 重新开始一个等待观察窗口;清零前先确认不影响正在进行的诊断
TRUNCATE TABLE performance_schema.events_waits_summary_by_thread_by_event_name;
-- 窗口结束后再次读取,避免把空线程或无事件行列入排序
SELECT THREAD_ID, EVENT_NAME, COUNT_STAR,
ROUND(SUM_TIMER_WAIT / 1000000000000, 6) AS sum_wait_seconds
FROM performance_schema.events_waits_summary_by_thread_by_event_name
WHERE COUNT_STAR > 0
ORDER BY SUM_TIMER_WAIT DESC
LIMIT 20;
清零只影响 Performance Schema 的内存汇总,不会修改业务表,也不会把它变成持久化历史。需要长期趋势时,应由外部监控按固定间隔读取并保存结果,而不是把一次汇总查询当成完整时间序列。
几个容易误判的边界
- 看到 THREAD_ID 不等于看到连接:先关联
threads,后台线程的PROCESSLIST_ID可能为空。 - 累计时间不等于墙上时钟:Performance Schema 计时值用于比较和排序,换算秒后仍要结合观察窗口解释。
- 没有行不一定没有问题:检查 instrument 的
ENABLED、TIMED、thread instrumentation 和对应 consumer。 - 汇总不是 SQL 根因:找到高等待线程后,还要结合当前语句、锁信息、表 IO 或应用请求链继续定位。
常见问题
为什么按线程汇总表只有少量记录? 可能是等待 instrument 未启用、没有计时,或者线程采集/consumer 没有覆盖目标事件。先查询 setup 表,再扩大观察范围。
为什么用 PROCESSLIST_ID 去查汇总表不生效? 汇总表按 THREAD_ID 聚合,连接 ID 在 threads.PROCESSLIST_ID 中,需要先做一次线程映射。
什么时候应该用 history 表? 要看最近单个事件的时间和对象时用 history;要比较某线程在一个窗口内的累计次数与等待时间时,用按线程 summary 表更直接。
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
501 收藏
-
118 收藏
-
271 收藏
-
368 收藏
-
335 收藏
-
175 收藏
-
374 收藏
-
154 收藏
-
432 收藏
-
232 收藏
-
287 收藏
-
233 收藏
-
417 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 485次学习