alter table会阻塞从库sql线程回放,因其在主库原子执行后仅记录最终状态到binlog,从库需完整重放重建过程,耗时长且易被mdl锁卡死;末尾加列可免重建,大幅降低延迟。

ALTER TABLE 会阻塞从库 SQL 线程回放
主库执行 ALTER TABLE 时,整个 DDL 过程在主库是原子性完成的:先加元数据锁(MDL),再重建表、拷贝数据、切换表名,最后释放锁。但 Binlog 只记录“执行完成后的最终状态”,不会记录中间过程。从库的 SQL Thread 拿到这个 DDL event 后,必须完整重放一遍——也就是在从库上也走一遍建新表 + 全量拷贝 + 切换的流程。这意味着:主库耗时 120 秒的 ALTER TABLE,从库大概率也要耗 120 秒(甚至更久,尤其当从库硬件弱或磁盘慢时),期间 Exec_Master_Log_Pos 几乎不动,Seconds_Behind_Master 持续飙升。
DDL 在从库可能被元数据锁卡住
如果从库同时有长事务、未提交的查询,或正在执行其他 DML 操作,ALTER TABLE 就会卡在 waiting for table metadata lock 状态。此时 Slave_SQL_Running_State 显示等待锁,Exec_Master_Log_Pos 完全停滞,延迟秒数只增不减。这不是“慢”,而是“堵死”。常见于从库承担读业务且未做连接隔离的场景。
- 用
SELECT * FROM information_schema.innodb_trx ORDER BY trx_started LIMIT 5;查看长事务 - 用
SHOW PROCESSLIST;找出对目标表有活跃操作的连接 - 必要时
KILL掉阻塞线程(注意业务影响)
末尾加列 vs 中间加列,延迟差异极大
InnoDB 对“在表末尾添加列”做了原地优化(无需重建表),而“在中间位置插入列”仍需全表重建。实测中,一张 500 万行的表:ALTER TABLE t ADD COLUMN c3 VARCHAR(10) AFTER c2; 可能耗时 90 秒;而 ALTER TABLE t ADD COLUMN c_new VARCHAR(10);(末尾)通常在 1 秒内完成。后者几乎不引发从库延迟,前者则必然拖垮复制进度。
- 优先使用末尾加列、删除列等免重建操作
- 避免
AFTER/BEFORE指定位置,除非业务强依赖字段顺序 - 大表 DDL 前务必确认从库资源水位(
iostat -x 1、top)
online DDL 并不能完全消除从库延迟
即使主库用了 ALGORITHM=INPLACE, LOCK=NONE,只要 Binlog 格式是 ROW,MySQL 仍会把整张表变更前后的镜像写入 Binlog(尤其涉及索引重建时)。从库收到后依然要逐行应用,I/O 和 CPU 压力不减。更关键的是:INPLACE 只降低主库锁表时间,并不改变从库单线程回放的本质——它只是把“一次大延迟”拆成“多次小延迟”,总量未必减少。
-
binlog_format = ROW下,大表ADD INDEX仍会导致从库 relay log 快速膨胀 - 从库若未开启并行复制(
slave_parallel_workers > 0),所有 DDL 相关 event 都串行处理 - DDL 后紧跟大量 DML 时,从库可能因 relay log 积压触发磁盘满或 OOM
真正难处理的不是“DDL 本身多慢”,而是它暴露了从库单线程回放 + 资源受限 + 无流量隔离的三重脆弱性。一旦遇到大表操作,延迟就不是“可预期的慢”,而是“不可控的断连风险”。











