优先使用 sys.schema_table_lock_waits 视图诊断 MDL 锁阻塞,因其扁平化输出 blocking_pid(持锁会话)、waiting_pid(被堵会话)及 sql_text(持锁语句),需确保 performance_schema=1 且 mdl 采集器启用;若 blocking_pid 为 NULL,则需联查 INNODB_TRX 与 PROCESSLIST 定位隐式事务悬挂,并通过 performance_schema.metadata_locks 验证锁类型与持有者。

直接查 sys.schema_table_lock_waits,它能一次性告诉你谁在堵谁,不需要拼表、不依赖经验判断。
为什么优先用 sys.schema_table_lock_waits?
这个视图是 MySQL 5.7+ 官方提供的诊断捷径,把阻塞关系扁平化输出:
-
blocking_pid就是真正持锁的会话 ID(不是那个显示Waiting for table metadata lock的) -
waiting_pid是被卡住的 DDL 或查询 -
sql_text字段常能直接看到持锁者最后执行的语句,比如BEGIN或一个长SELECT SLEEP(3600)
如果返回为空,先确认两件事:SELECT @@performance_schema 必须为 1;再执行 UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl' 开启采集器。否则视图没数据不是没锁,是没采到。
当 sys.schema_table_lock_waits 返回 blocking_pid 为 NULL 时怎么办?
这大概率是隐式事务悬挂——比如应用 BEGIN 后只跑了一条 SELECT 就断连了,连接在 PROCESSLIST 里状态是 Sleep,但事务仍活跃、MDL 锁没释放。
- 必须联查
INNODB_TRX和PROCESSLIST,单看任一表都会漏掉 - 关键筛选条件:
p.COMMAND = 'Sleep'且t.trx_state = 'RUNNING'且t.trx_started时间早于所有等待者 - 特别注意
TIME > 600且INFO为空的连接,90% 是应用忘记COMMIT或异常中断
用 performance_schema.metadata_locks 验证锁类型和持有者
SHOW PROCESSLIST 不显示 MDL 持锁信息,它只反映线程状态。真实持锁细节得靠 performance_schema.metadata_locks:
- 查持锁线程:
SELECT * FROM performance_schema.metadata_locks WHERE OWNER_THREAD_ID = ? AND LOCK_STATUS = 'GRANTED' - 重点看
LOCK_DURATION = 'TRANSACTION'+LOCK_TYPE IN ('SHARED_READ', 'SHARED_WRITE')→ 这是事务级 MDL 锁 - 再反查该线程当前语句:
SELECT PROCESSLIST_INFO FROM performance_schema.threads WHERE PROCESSLIST_ID = ?,若为空或只有SELECT,基本可安全KILL;若显示UPDATE或INSERT,就得先评估业务影响
最易被忽略的一点:blocking_pid 对应的会话,在 PROCESSLIST 中很可能显示为 Sleep,而不是 Query 或 Updating。别被状态骗了——MDL 锁从事务开启就挂着,跟当前有没有 SQL 正在跑无关。


















