查sys.schema_table_lock_waits是最直接方式,它聚合元数据锁阻塞关系,一行展示持锁事务id、线程pid及sql,专用于定位ddl被阻塞问题,不反映行锁冲突。

直接查 sys.schema_table_lock_waits,它能一眼看出谁在持锁、谁被卡住、为什么卡——这是 MySQL 8.0+ 最靠谱的入口,别再硬拼 INNODB_TRX 和 performance_schema.metadata_locks。
MySQL 8.0+ 必用 sys.schema_table_lock_waits
这张表是官方封装好的“阻塞关系图谱”,不需要手关联多张表。它默认启用,只要没被手动禁用过(sys 库存在即可)。
- 执行
SELECT * FROM sys.schema_table_lock_waits\G,结果里关键字段是:BLOCKING_TRX_ID(持锁事务)、BLOCKING_PID(可 kill 的线程 ID)、BLOCKING_SQL(持锁语句) - 如果
BLOCKING_SQL是空的,说明持锁者是隐式事务(比如autocommit=0下只执行了INSERT没COMMIT) - 注意:该视图只显示当前正在发生的阻塞链,不是历史记录;一旦锁释放,行就消失
MySQL 5.7 或无法用 sys 库时,退而求其次查 performance_schema.metadata_locks
这张表暴露的是元数据锁原始状态,但字段抽象、需人工过滤,容易漏判。
- 先确认是否启用:
SELECT * FROM performance_schema.setup_instruments WHERE NAME = 'wait/lock/metadata/sql/mdl';,若ENABLED是NO,得先UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl'; - 查持锁者:
SELECT * FROM performance_schema.metadata_locks WHERE LOCK_STATUS = 'GRANTED' AND OWNER_THREAD_ID IN (SELECT THREAD_ID FROM performance_schema.threads WHERE PROCESSLIST_ID IS NOT NULL); - 常见陷阱:同一张表可能有多个
GRANTED锁(比如 DDL + SELECT FOR UPDATE 同时存在),得结合LOCK_TYPE(如EXCLUSIVE)和OWNER_THREAD_ID判断哪个真正阻塞 DDL
KILL 前必须确认 PROCESSLIST_INFO 内容
元数据锁(MDL)只在连接断开时释放,KILL QUERY 不起作用——这点和 InnoDB 行锁完全不同。
- 务必先查:
SELECT PROCESSLIST_INFO FROM performance_schema.threads WHERE PROCESSLIST_ID = <code>blocking_pid;,确认它真在执行什么,而不是刚查完就挂起的慢查询 -
KILL <code>blocking_pid会断开连接并回滚事务,但业务层可能因此报错(比如未处理连接中断) - 如果
PROCESSLIST_INFO显示的是COMMIT或空,大概率是应用层卡住没发 COMMIT,这时杀掉比等更安全;如果显示的是长耗时SELECT,就得先评估影响
真正难的不是查到谁持锁,而是判断“该不该杀”。同一个 BLOCKING_PID,在报表导出场景下可能是合法长事务,在 OLTP 场景下就是故障源——上下文永远比 SQL 文本重要。











