真正卡住数据库的是COMMAND='Sleep'但trx_state='RUNNING'的长事务连接,它持MDL锁、阻塞DDL、滞留undo;应优先查sys.schema_table_lock_waits定位blocking_pid,再结合INNODB_TRX与PROCESSLIST确认并安全KILL。

真正卡住数据库的不是“Waiting for table metadata lock”的线程,而是背后那个看似安静、COMMAND = 'Sleep'却trx_state = 'RUNNING'的长事务连接。
查 sys.schema_table_lock_waits 快速定位阻塞源头
这是 MySQL 5.7+ 最直接有效的入口,它把谁堵了谁一次性列清楚,不用拼表、不靠猜:
-
blocking_pid是真正在持锁的连接 ID,不是显示“Waiting”的那个;waiting_pid才是被卡住的 DDL 或查询 -
sql_text字段能直接看到持锁者最后执行的语句(比如一个没提交的SELECT) - 如果返回为空,先确认
performance_schema已启用:SELECT @@performance_schema;必须为1 - 再检查 MDL 采集器是否打开:
UPDATE performance_schema.setup_instruments SET ENABLED = 'YES' WHERE NAME = 'wait/lock/metadata/sql/mdl'; -
blocking_pid为NULL不代表没锁——很可能是隐式事务(如BEGIN后只跑了一条SELECT就断开)在持锁
联合 INNODB_TRX 和 PROCESSLIST 找“Sleep 却 RUNNING”的悬挂事务
大量 MDL 阻塞源根本不在活跃 SQL 里,而是在那些 COMMAND = 'Sleep'、STATE 为空、但事务状态仍是 RUNNING 的连接上。它从 BEGIN 开始就一直占着 MDL_SHARED_READ 锁:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
- 必须用
JOIN查,单查INNODB_TRX会漏掉已断连但事务未清理的连接 - 重点关注:
TIME > 300且INFO为空 → 极大概率是应用异常中断或忘记COMMIT -
trx_isolation_level = 'REPEATABLE READ'时,哪怕只执行过一条SELECT,事务一启就持 MDL 锁 - 执行这句:
SELECT t.trx_id, t.trx_started, t.trx_state, t.trx_isolation_level, p.ID, p.USER, p.HOST, p.DB, p.COMMAND, p.TIME, p.STATE, p.INFO FROM information_schema.INNODB_TRX t JOIN information_schema.PROCESSLIST p ON t.trx_mysql_thread_id = p.ID WHERE p.COMMAND = 'Sleep' AND t.trx_state = 'RUNNING' ORDER BY t.trx_started;
用 performance_schema.metadata_locks 确认锁类型和持有者线程
SHOW PROCESSLIST 根本不显示谁在 hold MDL 锁,因为它是服务层锁,得靠这个表看真实状态:
- 先确认采集器已开:
SELECT * FROM performance_schema.setup_instruments WHERE NAME = 'wait/lock/metadata/sql/mdl';,确保ENABLED和TIMED都是YES - 查具体锁:
SELECT OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID FROM performance_schema.metadata_locks WHERE OBJECT_SCHEMA = 'your_db' AND OBJECT_NAME = 'your_table'; - 结合
performance_schema.threads可反查OWNER_THREAD_ID对应的连接信息(如PROCESSLIST_ID) - 注意区分
MDL_SHARED_READ(普通查询)和MDL_EXCLUSIVE(DDL),后者一旦被阻塞,整个表的结构变更都会停摆
最常被忽略的是:一个 Sleep 连接只要事务没结束,它就一直在持锁、占 undo、拖慢 purge——表面风平浪静,实则三重隐患同时发酵。处理时优先用 KILL QUERY blocking_pid,而不是直接 KILL blocking_pid,避免意外中断正在写 binlog 的事务。










