ddl在从库阻塞sql线程是因单线程串行重放、mdl锁升级及database级并行限制所致,根本解决需改用logical_clock模式或手动绕过执行。

从库执行DDL时SQL线程完全阻塞
DDL语句在从库是单线程串行重放的,ALTER TABLE这类操作一旦开始,SQL Thread会全程占用,期间所有后续事务(包括其他表的DML)都得排队等待。这不是“慢”,而是“停摆”——Exec_Master_Log_Pos长时间不动、Slave_SQL_Running_State卡在altering table或Waiting for dependent transaction to commit就是典型信号。
根本原因在于:MySQL 5.7默认的并行复制粒度是database(库级别),而DDL语句自带隐式FLUSH TABLES WITH READ LOCK语义,会强制整个库范围的串行化,哪怕你只改user_order一张表,同库下所有表的变更都得等它结束。
- 用
SHOW PROCESSLIST能直接看到SQL Thread的ID和状态,不是Sleep,而是明确显示DDL动作 -
Seconds_Behind_Master持续上涨且不回落,基本可排除IO线程问题 - 即使主库已写完binlog,从库relay log里也只有一条长事务记录,无法拆分并发
为什么slave_parallel_type=database对DDL无效
设置slave_parallel_workers=4却没效果?因为database模式只对DML生效:只要两个事务操作不同库,就能分发到不同worker线程。但DDL语句没有“库隔离”豁免权——它会触发全库级MDL锁升级,MySQL内核会自动将当前库下所有pending事务路由到同一个worker,实际退化为单线程。
更麻烦的是,DDL在binlog中是以Query_log_event形式记录的(非row格式),其common_header.timestamp取的是主库执行完成时刻,从库重放时无法按行级时间戳切片,逻辑时钟(logical_clock)机制也拿它没辙。
-
SHOW VARIABLES LIKE '%slave_parallel_type%'返回database,不代表DDL能并行 -
SHOW PROCESSLIST里看不到多个Worker线程在跑DDL相关任务 - 即便开了8个worker,
SHOW FULL PROCESSLIST仍只显示1个活跃的SQL线程处理DDL
真正有效的并行化路径:必须切到logical_clock
只有slave_parallel_type='logical_clock'(MySQL 5.7.22+)才可能让DDL“部分让出”执行窗口——前提是主库开启binlog_group_commit_sync_delay并配合binlog_transaction_dependency_tracking=WRITESET,让DDL前后的事务带上依赖时间戳。但这只是缓解,不是根治。
实操上更可靠的做法是:把DDL从“被动重放”转为“主动绕过”。即在从库上禁用SQL Thread,手动执行DDL(需提前校验主从数据一致性),再恢复复制。这要求你严格控制DDL类型——仅限ADD COLUMN、DROP INDEX等不改变行物理布局的操作。
- 切换前必须
STOP SLAVE,否则START SLAVE会立即重放积压日志,引发冲突 -
SET GLOBAL slave_parallel_type='logical_clock'后,要RESET SLAVE才能生效,旧relay log不识别新规则 - DDL执行期间,务必监控
performance_schema.metadata_locks,防止从库自身长事务阻塞自己
DDL延迟最常被忽略的硬伤:从库硬件与主库不匹配
很多人调了参数、换了模式,延迟还是高,最后发现从库磁盘是机械盘,主库是NVMe;或者从库CPU是4核,主库是32核。DDL本质是I/O密集型操作:ALTER TABLE ... ALGORITHM=INPLACE仍需大量随机读写临时文件,COPY算法更是全表扫描+重建。从库性能短板会被无限放大。
一个反直觉的事实:innodb_flush_log_at_trx_commit=0在从库开反而可能加剧延迟——因为日志刷盘滞后,导致checkpoint频繁触发,进一步抢占I/O带宽。真正该调的是innodb_io_capacity和innodb_read_io_threads,让从库I/O能力贴近主库规格。
- 不要只看
Seconds_Behind_Master数值,用iostat -x 1观察从库%util是否长期>90% -
pt-table-checksum跑一次,确认主从表行数一致,避免DDL中途因校验失败回滚 - DDL完成后,立刻查
information_schema.INNODB_TRX,确保没有残留事务持有MDL锁











