Waiting for table metadata lock是在等MDL_EXCLUSIVE锁,因此前未提交的SELECT/INSERT或Sleep连接仍持有MDL_SHARED_READ锁,二者互斥;ALGORITHM=INPLACE和LOCK=NONE无法避免元数据变更阶段的短暂X锁等待。

不是ALTER TABLE本身慢,是它被前面一个没释放的MDL读锁死死拦住了。
Waiting for table metadata lock到底在等什么
这个状态不是DDL卡在IO或CPU上,而是卡在元数据锁(MDL)申请环节。MySQL执行ALTER TABLE必须拿到MDL_EXCLUSIVE锁,而任何未提交的SELECT、INSERT、ORM隐式事务、甚至空闲Sleep连接,只要还持有对目标表的MDL_SHARED_READ锁,就会和写锁互斥——ALTER只能排队等。
常见诱因包括:
-
SELECT * FROM t后忘了COMMIT或ROLLBACK,事务开着就一直持锁 - Django/MyBatis等框架执行完“读已提交”预热查询,但没显式结束事务
- 连接池配置不当,应用取完连接没
close(),游标挂着,performance_schema.threads里能看到活跃会话但INNODB_TRX查不到 - 监控脚本跑了个没
LIMIT的全表SELECT,持续几小时不结束
ALGORITHM=INPLACE和LOCK=NONE为什么救不了你
这两个参数只控制“数据重排阶段”是否锁表,不管“元数据变更阶段”。DDL开始前和提交时仍需短暂升级到MDL_EXCLUSIVE锁来更新数据字典、写binlog——哪怕只持续几毫秒,只要此时有未释放的MDL_SHARED_READ,它就得等。
也就是说:
-
LOCK=NONE≠ 零等待:高并发下DML语句照样会排队抢MDL -
ALGORITHM=INPLACE≠ 全程无锁:页分裂、索引重建等操作仍需短时锁 - 加
NOT NULL字段却不带DEFAULT,MySQL会直接降级为ALGORITHM=COPY,全程锁表
怎么快速定位谁在攥着MDL读锁
别只盯着information_schema.INNODB_TRX,它只显示事务级活跃操作;MDL锁可能来自自动提交语句或空闲连接。真正有效的组合是:
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
查锁状态:
SELECT OBJECT_SCHEMA, OBJECT_NAME, LOCK_TYPE, LOCK_DURATION, LOCK_STATUS, OWNER_THREAD_ID FROM performance_schema.metadata_locks WHERE OBJECT_NAME = 'your_table' AND LOCK_STATUS = 'PENDING';
再关联线程找源头:
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';
重点盯LOCK_DURATION = 'TRANSACTION'的记录——这种锁生命周期和事务一致,最危险。
线上执行前必须做的三件事
别急着敲ALTER TABLE,先确认环境是否可控:
- 查当前是否有长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 60; - 查MDL阻塞链:
SELECT * FROM performance_schema.metadata_locks ml JOIN performance_schema.threads t ON ml.OWNER_THREAD_ID = t.THREAD_ID WHERE ml.LOCK_STATUS = 'PENDING' AND ml.OBJECT_SCHEMA = 'your_db'; - 查可疑空闲连接:
SHOW PROCESSLIST;中Command为Sleep且Time超过300秒的,大概率是应用没关连接
最容易被忽略的一点:MDL锁生命周期不依赖事务是否活跃,而依赖连接是否关闭、游标是否释放——一个Sleep连接只要没断开,就可能一直攥着读锁。










