drop table卡在waiting for table metadata lock是因为需获取mdl_exclusive锁,而未提交事务持有mdl_shared读锁与其互斥;即使事务无实际sql(如仅begin未commit),也会持续持锁阻塞ddl。

为什么 DROP TABLE 会卡在 Waiting for table metadata lock
DROP TABLE 被阻塞,不是它自己慢,而是它拿不到 MDL_WRITE 锁——这个锁被一个未提交的长事务死死攥着。只要那个事务还开着(哪怕只执行了 BEGIN 没任何 SQL),它就持续持有 MDL_READ 锁,而 DROP TABLE 必须等这个锁释放才能继续。
常见现象包括:
-
SHOW PROCESSLIST里看到DROP TABLE状态是Waiting for table metadata lock - 同时还有若干
SELECT、UPDATE也卡在这个状态,形成雪崩式堆积 - 查
INFORMATION_SCHEMA.INNODB_TRX发现某个TRX_STARTED时间远早于当前,但TRX_QUERY为空——说明它只是开了事务没干活,但锁一直没放
长事务怎么就拦住了 DROP TABLE
关键点在于:MySQL 的元数据锁(MDL)机制不区分“读”和“写”的语义强度,只看锁类型是否兼容。DROP TABLE 需要 MDL_EXCLUSIVE(等价于 MDL_WRITE),而任何活跃事务(哪怕只是空事务)在打开表时都会加 MDL_SHARED(MDL_READ)。这两者互斥。
也就是说,以下任意一种情况都足以拦停 DROP TABLE:
- 应用层 ORM(如 Django 的
atomic块)开启事务后异常退出,没COMMIT或ROLLBACK - 连接池配置不当,
AUTOCOMMIT=0的连接复用后残留未结束事务 - 监控脚本执行了无
LIMIT的全表SELECT,且没设查询超时
为什么 SHOW PROCESSLIST 看不到真正拦路的事务
SHOW PROCESSLIST 显示的是“正在等待”的线程,不是“正在持锁”的线程。真正挡路的那个长事务可能状态是 Sleep 或 Query 已结束,但它所属的事务仍处于 RUNNING 状态——只有查 INFORMATION_SCHEMA.INNODB_TRX 才能暴露它。
推荐诊断 SQL:
SELECT TRX_ID, TRX_MYSQL_THREAD_ID, TRX_STATE,
TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) AS trx_duration_sec,
TRX_QUERY
FROM INFORMATION_SCHEMA.INNODB_TRX
WHERE TIME_TO_SEC(TIMEDIFF(NOW(), TRX_STARTED)) > 10;
注意:TRX_QUERY 为空 ≠ 安全;trx_duration_sec > 10 就该介入,别等它到 60 秒才动手。
DROP TABLE 和 ALTER TABLE 在锁行为上其实没本质区别
很多人以为 DROP TABLE 是“删物理文件”,跟事务无关。错。它同样要走完整的 DDL 流程:先获取 MDL_EXCLUSIVE 锁 → 清理数据字典 → 刷 binlog → 最后才删 .ibd 文件。前面三步全卡在锁上。
所以别指望 ALGORITHM=INSTANT(MySQL 8.0.12+)能绕过这个问题——它只加速字段增删等轻量变更,对 DROP TABLE 无效。唯一解法是主动清理源头的长事务,而不是调大超时或重启实例。
最易被忽略的一点:长事务可能根本不在业务库,而在 information_schema 或 performance_schema 查询中产生——比如某些 DBA 工具或巡检脚本反复执行未带 LIMIT 的元数据扫描,它们一样会持 MDL 锁。











