一条 ALTER 在等锁,为什么后面所有 SELECT 都卡住了
MDL(元数据锁)是 MySQL 自动加在表上的锁:增删改查拿读锁,改表结构拿写锁。读锁之间能共存,写锁要独占,而且都要到事务结束才放。
复现了一下堵表现场:
A:BEGIN; SELECT * FROM cfg; -- 拿到 MDL 读锁,不提交
B:ALTER TABLE cfg ADD COLUMN ...; -- 要写锁,等 A
C:SELECT COUNT(*) FROM cfg; -- 普通查询,也在等C 明明和 A 一样只要读锁,为什么也等?因为 MDL 是排队的:在等的写锁请求优先,后来的读锁排在它后面。
于是 B 等 A,所有新查询等 B,整张表看起来被锁死。线上表现就是:一条 ALTER 卡住,接着连接池被占满,服务报超时。
MDL 和行锁是两套独立的锁:MDL 在 Server 层锁表结构,行锁在 InnoDB 锁具体的行。增删改查之间只在行锁上冲突,ALTER 和它们只在 MDL 上冲突。