查sys.innodb_lock_waits表是最直接的方式,它聚合底层锁表、免join、兼容mysql 8.0+,一行展示等待事务id、阻塞事务id、线程pid、sql及表索引等关键字段,配合sys.session可定位阻塞方当前语句。

查 sys.innodb_lock_waits 表是最直接的方式
这个视图把 information_schema.INNODB_TRX、INNODB_LOCKS(MySQL 8.0.1 之后已移除)、INNODB_LOCK_WAITS 等底层表做了聚合,能直接看到谁在等锁、等哪个对象、被谁阻塞。不需要自己 JOIN 多张表,也避开了 MySQL 8.0+ 中 INNODB_LOCKS 表不可用的问题。
执行这条语句就能拿到当前所有锁等待链:
SELECT * FROM sys.innodb_lock_waits;
关键字段包括:waiting_trx_id(等待事务ID)、blocking_trx_id(阻塞事务ID)、waiting_pid(等待线程PID)、blocking_pid(阻塞线程PID)、waiting_query(被卡住的 SQL)、blocking_query(默认为 NULL,因为阻塞方可能已执行完但未提交)、waiting_table 和 waiting_index(锁定的具体表和索引)。
配合 sys.session 查阻塞方正在执行什么
sys.innodb_lock_waits 不会显示阻塞方当前的 SQL(blocking_query 基本为空),得手动关联 sys.session 或 performance_schema.threads 才能看到它卡在哪条语句上。
推荐用这个组合查询:
SELECT w.waiting_pid AS '等待线程', w.waiting_query AS '等待语句',<br>s.conn_id AS '阻塞连接ID', s.command AS '命令类型', s.state AS '状态', s.current_statement AS '阻塞方当前语句'<br>FROM sys.innodb_lock_waits w<br>JOIN sys.session s ON w.blocking_pid = s.pid;
注意:sys.session 默认只显示活跃会话(conn_id IS NOT NULL),如果阻塞方是空闲连接(比如显式开启事务后没操作就挂起),current_statement 会是 NULL,这时得查 information_schema.INNODB_TRX 的 TRX_QUERY 和 TRX_STARTED 时间确认是否“睡着了”。
MySQL 9.6.0是面向Linux平台的2026年创新版本,核心架构迎来重大革新。其将外键约束与级联操作从InnoDB引擎层上移至SQL层,确保所有数据变更均被完整记录至Binlog,彻底解决了CDC(变更数据捕获)与主从复制中的数据不一致难题。此外,该版本引入container_aware启动选项以原生适配容器环境,并对审计日志进行了组件化重构,为追求极致数据一致性与云原生体验的开发者提供了全新选择。
为什么 sys.innodb_lock_waits 有时查不到记录?
常见原因有三个:
- 事务隔离级别是
READ COMMITTED或更低,且没有真正加锁(例如普通 SELECT 不加锁,SELECT ... FOR UPDATE在 RC 下只锁匹配行,不锁间隙) - 锁已被释放:阻塞方已提交或回滚,但等待方还没超时(此时
innodb_lock_waits已清空,但等待方仍卡在update或insert上) - Sys 库未启用:MySQL 5.7+ 默认安装但可能被禁用;检查
SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = 'sys';,若无结果需运行mysql_upgrade或手动安装
另外,sys.innodb_lock_waits 只反映“正在等待”的瞬间快照,不是历史日志。想持续追踪,得结合 performance_schema.data_locks(MySQL 8.0.1+)或定期采样。
performance_schema.data_locks 是更底层的替代方案
MySQL 8.0.1 起,INNODB_LOCKS 表被彻底移除,data_locks 成为唯一能实时看到“当前持有哪些锁”的表。它比 sys.innodb_lock_waits 多一层细节,但也更难读:
-
ENGINE固定为InnoDB -
OBJECT_SCHEMA和OBJECT_NAME指明库表名 -
INDEX_NAME为NULL表示表级锁(如LOCK TABLES),否则是行锁所在的索引 -
LOCK_TYPE值为RECORD(行锁)、TABLE(表锁)、GLOBAL(全局锁) -
LOCK_DATA显示被锁记录的主键值(如123),对联合主键会显示多个值,用逗号分隔
要定位具体哪条记录被锁,可以这样查:
SELECT OBJECT_SCHEMA, OBJECT_NAME, INDEX_NAME, LOCK_TYPE, LOCK_MODE, LOCK_DATA<br>FROM performance_schema.data_locks<br>WHERE OBJECT_SCHEMA = 'your_db' AND OBJECT_NAME = 'your_table';
注意:LOCK_DATA 是字符串,不能直接用于 WHERE 条件做精确匹配(比如 LOCK_DATA = '123' 可能漏掉联合主键场景),需要按需解析。
真正卡住的时候,往往不是单一锁点,而是多个事务形成环路或长事务拖慢整个锁队列。别只盯着第一个 waiting_query,顺着 blocking_pid 往上追两层,常会发现一个没提交的老事务在源头躺着。










