sys.innodb_lock_waits看不到Metadata Lock,因为MDL是Server层锁,不经过InnoDB;应通过performance_schema.metadata_locks或sys.schema_table_lock_waits定位阻塞。

查 sys.innodb_lock_waits 为什么看不到 Metadata Lock?
因为 sys.innodb_lock_waits 只展示 InnoDB 层的行锁/表锁等待,而 METADATA LOCK(MDL)是 Server 层的锁,完全不经过 InnoDB。盲目查这个视图会漏掉真正卡住你的会话。
正确入口是 performance_schema.metadata_locks 配合 performance_schema.threads —— 但默认关闭,必须提前启用:
SET GLOBAL performance_schema = ON;UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl';- 重启后才对新连接生效;已有连接不会自动捕获 MDL 事件
用 sys.schema_table_lock_waits 快速定位阻塞链
这是最省事的方案——sys 库里已封装好逻辑,只要 performance_schema 开启且 MDL 采集器启用,直接查:
SELECT * FROM sys.schema_table_lock_waits\G
它会返回:谁在等哪张表、等什么类型的 MDL(SHARED_READ / EXCLUSIVE 等)、谁持有锁、持有者正在执行什么语句(sql_text 字段)、是否已运行多久(processlist_time)。
注意点:
- 字段
object_schema和object_name是被锁的库和表,不是持有者当前操作的库表 - 若
blocking_pid为NULL,说明锁由隐式操作持有(比如未提交事务中的 DML 正在阻塞 DDL) - 该视图不显示
SLEEP或空闲连接,只抓活跃阻塞关系
手动关联 performance_schema 查完整上下文
当 schema_table_lock_waits 信息不够(比如想看持有者线程的完整堆栈或客户端 IP),就得自己 JOIN:
SELECT
l.OBJECT_SCHEMA,
l.OBJECT_NAME,
l.LOCK_TYPE,
l.LOCK_DURATION,
l.LOCK_STATUS,
t.PROCESSLIST_ID AS blocking_pid,
t.PROCESSLIST_INFO AS blocking_query,
t.PROCESSLIST_TIME AS blocking_time,
t.PROCESSLIST_HOST,
t.PROCESSLIST_USER
FROM performance_schema.metadata_locks l
JOIN performance_schema.threads t ON l.OWNER_THREAD_ID = t.THREAD_ID
WHERE l.LOCK_STATUS = 'PENDING'
AND l.OWNER_THREAD_ID IN (
SELECT OWNER_THREAD_ID FROM performance_schema.metadata_locks
WHERE LOCK_STATUS = 'GRANTED' AND OBJECT_SCHEMA = 'your_db' AND OBJECT_NAME = 'your_table'
);关键过滤逻辑:
- 先找出对目标表已持有
GRANTED锁的线程 ID - 再查哪些线程正对该表发起
PENDING请求,并关联到持有者线程详情 -
PROCESSLIST_INFO可能为NULL(比如线程在 sleep 或等待 IO),此时要看PROCESSLIST_COMMAND和PROCESSLIST_STATE
KILL 前务必确认持有者状态
MDL 持有者未必在跑长 SQL —— 很可能只是个没提交的事务、一个卡住的 ALTER TABLE、甚至一个忘了关的客户端连接。直接 KILL 可能导致:
- 事务回滚耗时极长(尤其大表 DML 后)
- DDL 中断后留下临时表或元数据不一致(MySQL 5.7+ 有部分恢复能力,但非绝对)
- 持有者是主库上的复制线程(
system user),KILL 会中断复制
安全做法:
- 先用
SHOW PROCESSLIST看blocking_pid的Command和State,排除Binlog Dump、Connect(从库)等系统线程 - 检查
INFORMATION_SCHEMA.INNODB_TRX,确认是否有未提交事务关联该线程 - 如果持有者是交互式客户端,优先联系对应负责人;别一上来就 KILL
MDL 的麻烦在于它不释放直到会话结束或显式释放(如 COMMIT / ROLLBACK / DROP TABLE),而很多阻塞其实源于开发习惯:事务里混写 DML 和 DDL、用 GUI 工具开事务后切走、或者脚本异常退出没 cleanup。


















