ddl卡在waiting for table metadata lock时,真正阻塞ddl的是未提交事务持有的shared_read mdl锁,而非查询本身;需通过information_schema.innodb_trx查trx_started时间戳定位长事务,kill pid强制回滚释放锁,kill query无效。

DDL卡在Waiting for table metadata lock时,长查询真正在阻塞什么?
不是“查询本身”在阻塞DDL,而是它背后那个没提交的事务持有的MDL读锁(SHARED_READ)在拦路。哪怕只执行了一条SELECT * FROM t,只要在BEGIN之后没COMMIT或ROLLBACK,这个锁就一直挂着——DDL需要的EXCLUSIVE MDL锁根本拿不到。
常见错误现象:SHOW PROCESSLIST里看到一堆State: Waiting for table metadata lock,但阻塞源头可能是个Command: Sleep、Time: 320、Info为空的连接,很容易被当成“空闲连接”忽略。
为什么KILL QUERY无效,必须用KILL?
KILL QUERY <code>pid只中断当前语句,事务状态仍是RUNNING,MDL锁不释放;只有KILL <code>pid才会强制断开连接,触发事务回滚,真正释放锁。
- 别对正在执行
ALTER TABLE的线程执行KILL——它只是在等锁,杀掉后重试照样卡住 - 如果
INNODB_TRX里查不到明显长事务,但PROCESSLIST里大量连接Time很大,可能是应用连接池未回收,得从应用侧查配置 - 用
SELECT * FROM performance_schema.threads WHERE PROCESSLIST_ID = <code>pid确认PROCESSLIST_INFO内容,避免误杀正在跑重要报表的连接
如何快速定位真正该杀的长事务?
靠SHOW PROCESSLIST不够,得查information_schema.INNODB_TRX里的trx_started时间戳——这才是事务真实起始时间。
实操命令:
SELECT trx_id, trx_started, trx_state, trx_mysql_thread_id,
SUBSTRING_INDEX(trx_query,' ', 4) AS short_query
FROM information_schema.INNODB_TRX
WHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 120;
重点看:short_query是不是SELECT或空,trx_state是不是RUNNING但trx_started远早于当前时间(比如5分钟前)。
MySQL 8.0+ 更推荐直接查sys.schema_table_lock_waits,它能直接给出BLOCKING_PID和BLOCKING_SQL,省去连表拼接。
杀完就万事大吉?这几个坑还在后面
杀掉长事务只是解燃眉之急,真正麻烦的是:事务回滚本身可能耗时很长(尤其涉及大量修改),期间依然持有行锁、undo日志持续增长;如果被杀的是一个正在做批量更新的写事务,应用层没做幂等处理,重试后可能重复写入。
最容易被忽略的一点:autocommit=0模式下,哪怕只执行一条INSERT没COMMIT,也会持锁——这不是性能问题,是MDL协议本身的刚性约束,没法绕过。











