当前位置:首页 > 文章列表 > 数据库 > MySQL > MySQL Performance Schema 按线程聚合等待事件

MySQL Performance Schema 按线程聚合等待事件

来源:17golang原创 2026-10-31 23:26:59 0浏览 收藏

排查 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_IDPerformance Schema 内部线程标识关联 threads,不要直接当连接 ID
EVENT_NAME等待 instrument 名称区分文件、同步、表 IO 等等待类别
COUNT_STAR汇总事件次数判断频繁等待
SUM_TIMER_WAIT已计时等待的累计时长排序寻找累计影响较大的线程
AVG_TIMER_WAIT已计时等待的平均时长区分高频短等待和低频长等待

官方手册说明,计时值在读取时以皮秒展示,所以查询时应换算成秒或微秒。没有计时的 instrument,其计时列可能为 NULL;不要把这类空值解释为“没有等待”。

MySQL 按线程聚合等待事件的静态关系说明图,展示线程、等待汇总和连接映射
图1:结构说明图,查看 THREAD_ID、等待汇总表与连接线程之间的静态关系;这不是运行截图。

采集项没有打开时,为什么查询不到有用数据

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 一定是根因。

MySQL 线程等待排查的静态结构说明图,展示 THREAD_ID 到连接字段和等待指标的关系
图2:结果说明图,展示线程 ID 到连接字段、事件次数与计时指标的静态关系;这不是线上结果截图。

用时间窗口清零,避免把旧累计量当成新故障

汇总表会持续累计,适合看窗口内的趋势,但不适合直接代表“刚刚发生的故障”。开始一次排查前,可以记录当前值;需要完全重开窗口时,按官方允许的方式清零汇总表,然后等待一个固定观察周期再查询:

-- 重新开始一个等待观察窗口;清零前先确认不影响正在进行的诊断
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 表更直接。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
MySQL 事务隔离级别与锁定读的组合方案MySQL 事务隔离级别与锁定读的组合方案
上一篇
MySQL 事务隔离级别与锁定读的组合方案
Redis XINFO STREAM 统计首尾消息与消费组状态
下一篇
Redis XINFO STREAM 统计首尾消息与消费组状态
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    816次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    807次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    899次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    870次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    693次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码