MySQL从库SQL Thread执行DDL时强制串行,不参与并行复制,因DDL以Query_log_event记录、无法切片,且需全局MDL锁,导致后续所有事件阻塞;手动在从库执行并跳过重放是最可靠绕过方式。

DDL在从库是单线程串行重放的
MySQL从库的SQL Thread处理DDL时不会并发,哪怕你设了slave_parallel_workers=8,也只看到1个线程在跑altering table。这是因为DDL在binlog里以Query_log_event形式记录,不是row格式,无法按时间戳或writeset切片——logical_clock机制对它完全失效。
常见现象包括:SHOW PROCESSLIST里SQL Thread状态卡在Waiting for table metadata lock或altering table;Exec_Master_Log_Pos长时间不动;Seconds_Behind_Master持续上涨却不回落。
- 这不是“慢”,是停摆:主库5秒完成的
ALTER TABLE,可能让从库积压上百个DML事务排队等待 -
slave_parallel_type=database对DDL完全无效——DDL会触发全库级MDL锁升级,所有同库事务被迫路由到同一个worker - 即使开了
binlog_transaction_dependency_tracking=WRITESET,也只能缓解前后DML的并行,DDL本身仍独占SQL Thread
从库MDL锁被长查询/备份意外持有
DDL执行需获取表级元数据锁(MDL),但若从库正运行慢查询、报表JOIN、SELECT ... FOR UPDATE,或正在跑mysqldump/xtrabackup,就会直接卡住SQL Thread。
典型信号:SHOW PROCESSLIST里能看到一个或多个线程State为Waiting for table metadata lock,且Command是Query或Sleep,它们就是锁持有者。
- 优先查并杀掉无关会话:
KILL [id](避开业务连接) - 禁止在从库执行未加索引的
WHERE、大范围JOIN、显式加锁语句 - 检查是否正在运行备份:
SHOW PROCESSLIST里找FTWRL或Flushing tables状态
原生ALTER不解决从库阻塞,ALGORITHM=INPLACE也没用
主库加ALGORITHM=INPLACE、LOCK=NONE只能减少主库锁表时间,对从库复制毫无帮助。从库回放时仍需申请相同MDL锁,只要锁被占,照样卡住。
更麻烦的是:DDL必须完整执行完,后续所有binlog事件才开始处理——延迟不是累加的,是“堵死”的。
- 别信“开了并行复制就没事”:DDL根本不在并行调度范围内
-
innodb_flush_log_at_trx_commit=1或sync_binlog=1会进一步拖慢DDL回放速度 - 主库刚执行完
ALTER,从库延迟突增几百秒,基本可判定是DDL阻塞而非网络或IO问题
绕过卡顿最可靠的实操路径是手动执行+校验
与其等SQL Thread硬扛,不如把DDL从“被动重放”转为“主动绕过”。这是目前线上最稳定、影响最小的做法。
- 先
STOP SLAVE暂停复制 - 用
pt-table-checksum或mysqldiff确认主从对应位点数据一致 - 在从库手动执行相同DDL(注意检查是否真支持
LOCK=NONE,否则仍会锁表) -
START SLAVE恢复,观察Seconds_Behind_Master是否快速归零
容易被忽略的关键点:手动执行前必须确认从库没有长事务正在访问该表,否则一样卡在Waiting for table metadata lock;另外SET sql_log_bin=0后执行的DDL不会写入binlog,主库不会同步,得业务侧接受短暂结构不一致。


















