information_schema.innodb_lock_waits 总是空的,因为它是瞬态视图,仅实时记录未超时且未释放的锁等待;mysql 8.0+ 应使用 performance_schema.data_lock_waits(需提前启用相关 instruments 和 consumers)并关联 innodb_trx 定位阻塞链。

为什么直接查 INFORMATION_SCHEMA.INNODB_LOCK_WAITS 总是空的
因为 INNODB_LOCK_WAITS 是一个“瞬态视图”,只记录当前**正在发生且尚未超时或释放**的阻塞关系。一旦被阻塞的事务回滚、提交,或者锁等待超时(默认 innodb_lock_wait_timeout=50 秒),对应行就立刻消失。你执行 SELECT * FROM INFORMATION_SCHEMA.INNODB_LOCK_WAITS 时没结果,大概率不是没阻塞,而是“刚好没拍到”。
真正可靠的起点是先看谁在等锁、谁持有锁:
- 查
INFORMATION_SCHEMA.INNODB_TRX找出所有活跃事务,重点关注TRX_STATE = 'LOCK WAIT'的行 - 查
INFORMATION_SCHEMA.INNODB_LOCKS(MySQL 8.0.1 之后已移除)→ 实际应转向performance_schema.data_locks和data_lock_waits - MySQL 8.0+ 必须用
performance_schema体系,INFORMATION_SCHEMA.INNODB_LOCK_WAITS已废弃且为空
MySQL 8.0+ 正确查阻塞链:用 performance_schema.data_lock_waits
这个表才是现代 MySQL 的“真·锁等待视图”,它实时反映事务间因行锁/表锁产生的等待依赖。但要注意:默认关闭,需手动启用。
实操步骤:
- 确认开关已开:
SELECT * FROM performance_schema.setup_instruments WHERE NAME LIKE 'wait/lock%';,确保wait/lock/innoDB/lock等相关项为ENABLED - 启用事件收集:
UPDATE performance_schema.setup_consumers SET ENABLED = 'YES' WHERE NAME IN ('global_instrumentation', 'thread_instrumentation'); - 查阻塞关系:
SELECT r.trx_id waiting_trx_id, r.trx_mysql_thread_id waiting_pid, r.trx_query waiting_query, b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_pid, b.trx_query blocking_query FROM performance_schema.data_lock_waits w JOIN information_schema.INNODB_TRX b ON b.trx_id = w.BLOCKING_ENGINE_TRANSACTION_ID JOIN information_schema.INNODB_TRX r ON r.trx_id = w.REQUESTING_ENGINE_TRANSACTION_ID;
注意:data_lock_waits 中的 ID 是引擎内部事务 ID(ENGINE_TRANSACTION_ID),必须关联 INNODB_TRX 的 trx_id 字段(类型一致),不能误连 trx_mysql_thread_id。
快速定位阻塞源头:结合 PROCESSLIST 和锁信息
光知道谁在等、谁在堵还不够,得立刻看到对应 SQL 和连接状态,方便 kill 或优化。
- 查被堵住的会话:
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST WHERE ID IN (SELECT trx_mysql_thread_id FROM INFORMATION_SCHEMA.INNODB_TRX WHERE TRX_STATE = 'LOCK WAIT'); - 查持锁会话的完整 SQL:
SELECT trx_id, trx_mysql_thread_id, trx_query, trx_started FROM INFORMATION_SCHEMA.INNODB_TRX WHERE trx_id IN (SELECT BLOCKING_ENGINE_TRANSACTION_ID FROM performance_schema.data_lock_waits); - 检查是否是长事务:对比
trx_started和当前时间,超过几分钟的TRX_STATE = 'RUNNING'事务极可能是锁持有者(未提交) - 避免误杀:
KILL前先SELECT * FROM performance_schema.threads WHERE PROCESSLIST_ID = ?确认该线程状态和用户,防止干掉关键后台任务
常见误判和性能陷阱
锁等待不等于死锁,data_lock_waits 不会自动标出死锁;死锁检测由 InnoDB 自动完成,并记录到错误日志(SHOW ENGINE INNODB STATUS 的 LATEST DETECTED DEADLOCK 部分)。
-
data_locks表数据量大时查询慢:加LIMIT,或按ENGINE_TRANSACTION_ID过滤后再 JOIN - 应用端连接池复用导致
trx_mysql_thread_id频繁变化:别只看 PID,优先用trx_id和trx_started定位逻辑事务 - 隐式锁(如唯一键冲突)不会出现在
data_locks中,但会引发等待 —— 此时只能靠INNODB_TRX+ 慢日志交叉分析 - 监控脚本里别长期轮询
data_lock_waits:它本身是采集型视图,高频查可能加重 performance_schema 开销
真正难的不是查到阻塞,而是判断那个持锁事务为什么迟迟不提交 —— 往往藏在应用层的事务边界模糊、异常未 rollback、或跨服务调用卡顿里。











