“Waiting for table metadata lock”是元数据锁(MDL)阻塞所致,非表数据锁;只要存在未提交的SELECT、INSERT或Sleep连接访问过该表,ALTER就无法获取排他MDL锁而持续等待,需通过performance_schema.metadata_locks定位持锁会话并KILL终止。

卡在 Waiting for table metadata lock 是什么情况
这不是表数据被锁,是元数据锁(MDL)阻塞。只要有个未提交的 SELECT、INSERT 或 Sleep 连接碰过这张表,ALTER 就拿不到排他 MDL 锁,只能干等。
典型现象:SHOW FULL PROCESSLIST 里看到一堆状态为 Waiting for table metadata lock 的线程,同时伴随若干 Command = Sleep、Time > 300、Info = NULL 的连接——它们大概率就是持锁不放的源头。
-
information_schema.INNODB_TRX查不到长事务?别慌,MDL 锁和事务不完全绑定:自动提交语句、ORM 隐式事务、甚至游标没 close 都可能留下MDL_SHARED_READ - 真正要盯的是
performance_schema.metadata_locks,执行:SELECT OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS FROM performance_schema.metadata_locks WHERE OBJECT_NAME = 'your_table';
重点关注LOCK_DURATION = 'TRANSACTION'的记录
为什么加了 ALGORITHM=INPLACE 还卡住
ALGORITHM 和 LOCK 参数只影响物理变更阶段,但 DDL 开始和结束时仍需短暂获取 MDL_EXCLUSIVE 锁。哪怕全程走 INPLACE,只要此时有其他会话持有 MDL_SHARED_READ,它照样排队。
常见“静默退化”场景:
- 表含全文索引(MySQL 5.6 中直接触发
ALGORITHM=COPY) - 存在外键约束(5.6–5.7.5 不支持 INPLACE 添加字段)
- 字符集或排序规则不一致(比如原表用
utf8mb4_general_ci,新字段指定utf8mb4_0900_as_cs) - MySQL 版本是 5.6 且没显式指定
ALGORITHM和LOCK
报错 ERROR 1846 (HY000): ALGORITHM=INPLACE is not supported 时,先跑 SHOW CREATE TABLE your_table 对比字段定义细节,别硬 retry。
怎么快速终止卡住的 ALTER TABLE
不能只 kill 掉那个 ALTER 线程——它只是受害者,不是加锁者。得先定位并干掉真正 hold 住 MDL 的会话。
- 查活跃事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - trx_started) > 60; - 查持锁线程:
SELECT t.PROCESSLIST_USER, t.PROCESSLIST_HOST, t.PROCESSLIST_INFO FROM performance_schema.threads t JOIN performance_schema.metadata_locks m ON t.THREAD_ID = m.OWNER_THREAD_ID WHERE m.OBJECT_NAME = 'your_table' AND m.LOCK_STATUS = 'PENDING'; - 确认无误后,用
KILL [thread_id]终止对应连接;若应用层有连接池,记得同步修复泄漏逻辑,否则下次还复现
大表改结构该不该直接 ALTER
千万级表上直接 ALTER TABLE 基本等于主动制造服务中断。MySQL 8.0.12+ 也只对极少数操作(如末尾加列且无 DEFAULT)真正支持 INSTANT,其余多数仍需全表扫描或重建。
生产环境更稳的选择是绕开 MDL 锁本身:
- 用
pt-online-schema-change:新建影子表 + 触发器同步 + 分块拷贝 + 原子切换,读写基本不受影响 - 前提条件必须满足:原表有主键或唯一非空索引;不能已有触发器;执行前加
--dry-run --print看生成 SQL 是否合理 - 严禁在从库单独运行再切主从——
pt-osc不复制 DDL,会导致主从结构不一致
真正难的不是“怎么执行 ALTER”,而是判断“要不要执行 ALTER”。很多卡死问题,根源不在命令本身,而在没提前清理长事务、没核对字符集兼容性、也没评估好业务容忍窗口。这些细节漏掉一个,就足以让线上服务停摆十几分钟。


















