mysql大表ddl会立即申请mdl写锁,阻塞所有后续读写请求;长事务持mdl读锁导致ddl无限期等待(默认超时365天),引发连接池打满、从库延迟暴涨及雪崩式阻塞。

大表DDL会触发MDL写锁,阻塞所有后续读写请求
MySQL执行ALTER TABLE时,必须先获取元数据锁(MDL)的排他写锁。这个锁不是等DDL真正开始才加,而是一发起就申请——只要它在等待队列里排队,后续所有SELECT、INSERT、UPDATE、DELETE都会被卡住,连带连接池快速打满。
常见错误现象:SHOW PROCESSLIST里大量线程状态为Waiting for table metadata lock;Seconds_Behind_Master暴涨且不回落;应用层报错“Lock wait timeout exceeded”。
- 长事务是最大隐形推手:一个未提交的
SELECT或DML会持MDL共享读锁,导致DDL无限期等待 -
lock_wait_timeout默认是31536000秒(365天),意味着DDL可能卡住一年,而新请求全在它后面排队 - 业务高峰期并发高,长事务概率大,锁等待链极易雪崩
Online DDL ≠ 完全无锁,LOCK=NONE有前提条件
即使MySQL 5.6+支持ALGORITHM=INPLACE, LOCK=NONE,也只对添加二级索引这类操作真正生效。一旦表存在外键、触发器、全文索引、或者有活跃长事务,MySQL会悄悄降级为ALGORITHM=COPY,全程锁表。
实操建议:
- 执行前务必用
EXPLAIN FORMAT=JSON确认"alter_algorithm": "inplace"和"lock": "none" - 若返回
"lock": "shared",说明写操作会被阻塞,必须避开高峰 -
innodb_file_per_table必须为ON,否则强制退化为COPY模式 - 检查
innodb_online_alter_log_max_size是否足够——Row Log溢出会导致DDL失败
从库延迟会放大问题,且无法靠并行复制缓解
主库上ALTER TABLE完成很快,但binlog传到从库后,SQL线程是单线程重放的。DDL语句自带隐式FLUSH TABLES WITH READ LOCK语义,在slave_parallel_type=database下会锁住整个库,同库其他表的DML也得排队。
关键点:
-
SHOW PROCESSLIST中SQL Thread状态长时间卡在altering table,就是典型信号 - 即便开了8个worker线程,DDL也无法并行——logical_clock模式也仅能缓解,不能根治
- 高峰期主库DDL一发,从库延迟数小时,读写分离架构直接读到脏/旧数据
资源冲击真实存在:IO、CPU、磁盘空间三重压力
大表加索引本质是遍历全表构建B+树,期间会大量读取数据页进buffer pool,同时写入索引页和Row Log。这会打满磁盘IO、抢占CPU、挤占内存缓存,连带正常查询响应变慢甚至超时。
更隐蔽的风险:
- COPY模式需要1–2倍临时磁盘空间,高峰期磁盘告警可能直接触发OOM或服务宕机
- 全表扫描会把热数据从buffer pool中刷出去,DDL结束后查询性能反而短暂下降
- pt-online-schema-change虽绕过锁表,但触发器复制本身会增加主库CPU和网络负载
真正危险的不是DDL花了多久,而是它让业务“不可见地卡住”的那几十秒——连接池耗尽、超时雪崩、监控失灵,这些往往发生在你还没意识到出问题的时候。











