MySQL performance_schema events_transactions_current 怎样抓住长事务
线上出现锁等待时,先不要把所有慢 SQL 都当成根因。对“事务还没结束、已经持续很久”的判断,MySQL Performance Schema 已经给了一个直接入口:performance_schema.events_transactions_current。筛选 STATE = 'ACTIVE'、END_EVENT_ID IS NULL,再把 TIMER_WAIT 从皮秒换算成秒,就能先抓住当前仍在运行的长事务。
本文只讨论当前事务、长事务和锁诊断,不把历史事务表当成实时列表,也不把事务持续时间直接等同于锁等待时间。
先确认当前事务事件确实在采集
events_transactions_current 按线程保存最近一个被监控的当前事务事件,每个线程最多对应一行。若事务 instrument 没开,或者 consumer 没开,查询为空并不代表系统没有事务。
-- 先查看事务采集开关,避免把“未采集”误判成“没有长事务” SELECT NAME, ENABLED, TIMED FROM performance_schema.setup_instruments WHERE NAME = 'transaction'; -- current consumer 决定是否维护当前事务表 SELECT NAME, ENABLED FROM performance_schema.setup_consumers WHERE NAME = 'events_transactions_current'; -- 仅在确认允许动态调整采集时执行;TIMED=YES 才能获得耗时字段 UPDATE performance_schema.setup_instruments SET ENABLED = 'YES', TIMED = 'YES' WHERE NAME = 'transaction'; UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME = 'events_transactions_current';

生产环境调整前要评估采集开关的影响,并确认账号有访问 Performance Schema 设置表的权限。文章中的 UPDATE 是配置示例,不代表已经在你的实例执行。
用 TIMER_WAIT 抓仍然活跃的长事务
MySQL 8.4 文档说明,当前事件尚未结束时,END_EVENT_ID 为 NULL,TIMER_WAIT 表示从开始到当前时刻经过的时间,单位是皮秒。下面用 300 秒作为排查阈值,你可以按业务事务的正常时长调整。
-- 300 秒 = 300 × 10^12 皮秒;只看仍处于 ACTIVE 的当前事务
SELECT
THREAD_ID,
EVENT_ID,
STATE,
ROUND(TIMER_WAIT / 1000000000000, 1) AS elapsed_seconds,
ACCESS_MODE,
ISOLATION_LEVEL,
AUTOCOMMIT,
NESTING_EVENT_ID,
NESTING_EVENT_TYPE
FROM performance_schema.events_transactions_current
WHERE END_EVENT_ID IS NULL
AND STATE = 'ACTIVE'
AND TIMER_WAIT IS NOT NULL
AND TIMER_WAIT >= 300 * 1000000000000
ORDER BY TIMER_WAIT DESC;
这里的三个条件各有作用:END_EVENT_ID IS NULL 排除已经结束但仍留在当前表的事件;STATE = 'ACTIVE' 把关注点放在尚未提交或回滚的事务;TIMER_WAIT IS NOT NULL 避免未计时的事件进入比较。若结果为空,先回到上一节检查采集开关和查询权限。
别把事务时间和锁等待时间混为一谈
长事务只是“事务保持活动的时间很长”,它可能在等待业务输入、持有锁、执行慢查询,或者只是应用忘记提交。要判断它是否正在阻塞别人,需要把事务线程与 performance_schema.data_lock_waits 关联。
-- requesting 是等待锁的一方,blocking 是持有阻塞锁的一方
SELECT
w.REQUESTING_THREAD_ID,
w.BLOCKING_THREAD_ID,
ROUND(r.TIMER_WAIT / 1000000000000, 1) AS requesting_seconds,
ROUND(b.TIMER_WAIT / 1000000000000, 1) AS blocking_seconds,
r.STATE AS requesting_state,
b.STATE AS blocking_state,
r.ACCESS_MODE AS requesting_mode,
b.ACCESS_MODE AS blocking_mode
FROM performance_schema.data_lock_waits AS w
LEFT JOIN performance_schema.events_transactions_current AS r
ON r.THREAD_ID = w.REQUESTING_THREAD_ID
LEFT JOIN performance_schema.events_transactions_current AS b
ON b.THREAD_ID = w.BLOCKING_THREAD_ID
WHERE r.END_EVENT_ID IS NULL
OR b.END_EVENT_ID IS NULL;

如果 BLOCKING_THREAD_ID 对应的事务持续时间很长,同时又出现在多个等待关系中,它更值得优先处理。但不要仅凭这张表直接终止会话:先结合业务确认是否处在必须原子完成的流程,再决定提交、回滚或让应用修复事务边界。
需要更具体的引擎信息时再看 InnoDB 状态
events_transactions_current 适合回答“哪个线程有一笔仍活跃的事务、已经持续多久、事务属性是什么”。当问题进一步变成“具体锁住了哪个索引记录、出现了什么 InnoDB 锁描述”,可以补充:
-- 该命令需要 PROCESS 权限;它提供 InnoDB Monitor 的引擎侧状态 SHOW ENGINE INNODB STATUS;
它们的分工可以这样记:当前事务表负责按线程和耗时排序,data_lock_waits 负责看等待与阻塞关系,InnoDB 状态负责补充引擎侧细节。三者不是同一份数据,也不能互相替代。
常见误区与速查结论
- 查询
events_transactions_history只能看到已经结束的近期事务,不能代替 current 表抓实时长事务。 TIMER_WAIT是皮秒,不是秒;换算时使用1000000000000,不要直接和 300 比较。- 事务很长不必然代表它正在阻塞别人;是否阻塞要看
data_lock_waits的 blocking 关系。 - 事务事件边界和服务器事务状态基本一致,但只访问非事务表的语句不会让 Performance Schema 事务事件进入同一事务边界。
排查顺序可以压缩成一句话:先确认采集,再用 END_EVENT_ID、STATE 和 TIMER_WAIT 找出活动长事务,随后用线程 ID 关联锁等待,最后用 InnoDB 状态补足记录级信息。
相关问题
为什么 TIMER_WAIT 是 NULL?
通常是对应 instrument 没有开启计时,即 TIMED 不是 YES。先查看 setup_instruments,不要把 NULL 当成零秒。
events_transactions_current 为什么看不到我刚执行的事务?
检查 Performance Schema 是否启用、transaction instrument 和 current consumer 是否开启,并确认事务确实访问了事务性存储引擎。自动提交模式下,每条使用事务性引擎的语句也可能形成很短的隐式事务。
长事务应该立刻 KILL 吗?
不建议只按时长自动处理。先确认它是否是阻塞链中的 blocking 方、是否处在可安全回滚的业务阶段,再由业务负责人决定提交、回滚、终止会话或修复连接池的事务边界。
MySQL 在线 DDL 怎样判断操作是否会阻塞写入
- 上一篇
- MySQL 在线 DDL 怎样判断操作是否会阻塞写入
- 下一篇
- MySQL 连接池空闲断开后应用为什么出现坏连接
-
- 数据库 · MySQL | 25分钟前 | MySQL · 连接池 ·
- MySQL 连接池空闲断开后应用为什么出现坏连接
- 254浏览 收藏
-
- 数据库 · MySQL | 31分钟前 | MySQL · InnoDB · mysql ALTER TABLE 元数据锁 在线DDL ALGORITHM=INPLACE LOCK=NONE
- MySQL 在线 DDL 怎样判断操作是否会阻塞写入
- 439浏览 收藏
-
- 数据库 · MySQL | 32分钟前 | mysql binlog redo log innodb_flush_log_at_trx_commit sync_binlog
- MySQL redo log 与 binlog 刷盘选项怎么配合
- 365浏览 收藏
-
- 数据库 · MySQL | 34分钟前 |
- MySQL PARTITION BY HASH 的数据分布为什么不均
- 209浏览 收藏
-
- 数据库 · MySQL | 35分钟前 |
- MySQL generated column 怎样把 JSON 字段提取成可索引列
- 261浏览 收藏
-
- 数据库 · MySQL | 39分钟前 | mysql 执行计划 EXPLAIN ANALYZE 慢查询排查 loops actual time
- MySQL EXPLAIN ANALYZE 中 actual time 两个数怎么读
- 130浏览 收藏
-
- 数据库 · MySQL | 40分钟前 | MySQL · 执行计划 · InnoDB · mysql ALTER INDEX 索引可见性 INVISIBLE 索引删除 DROP INDEX
- MySQL ALTER INDEX INVISIBLE 与删除索引的运维区别
- 376浏览 收藏
-
- 数据库 · MySQL | 43分钟前 | 数据库开发 · MySQL教程 · mysql JSON_TABLE JSON查询 NESTED PATH FOR ORDINALITY 父行
- MySQL JSON_TABLE NESTED PATH 没匹配时怎样保留父行
- 170浏览 收藏
-
- 数据库 · MySQL | 47分钟前 | MySQL · mysql 递归深度 WITH RECURSIVE cte_max_recursion_depth 递归查询
- MySQL recursive CTE 怎样用 cte_max_recursion_depth 控制深度
- 308浏览 收藏
-
- 数据库 · MySQL | 48分钟前 | mysql 窗口函数 并列排名 ROW_NUMBER RANK
- MySQL ROW_NUMBER 与 RANK 在并列记录时怎么选
- 194浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 1018次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 1020次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 1155次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 1121次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 962次使用
-
- 用查询属性把页面或请求来源传给当前 SQL 并在服务器端读取
- 2026-11-05 501浏览
-
- MySQL JSON_TABLE 展开数组时如何保留缺失字段
- 2026-09-10 501浏览
-
- MySQL 分区表怎么处理跨分区唯一键:分区列约束与建表取舍
- 2026-08-30 501浏览
-
- MySQL权限管理设置全攻略
- 2026-03-29 501浏览
-
- MySQL分片实现方法及常见方案解析
- 2025-06-24 501浏览

