根本原因是主库binlog_row_image非FULL或表缺失主键/唯一键导致写集为空,从库无法判断事务冲突而退化为单线程回放;需确保binlog_row_image=FULL、binlog_transaction_dependency_tracking=WRITESET、slave_preserve_commit_order=OFF(纯从库)且避免大DDL阻塞。

MySQL从库配置了slave_parallel_workers但Seconds_Behind_Master照涨不跌,根本原因不是“开了多线程就自动并行”,而是并行复制的触发条件没满足——绝大多数情况下,是写集(writeset)没生成出来,导致所有事务退化为单线程回放。
slave_parallel_type=LOGICAL_CLOCK 但 WORKERS_PROCESSED 一直为 0
这是最典型的“假开启”现象。即使你执行了SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK'和SET GLOBAL slave_parallel_workers = 12,只要从库没真正分发事务给 worker 线程,performance_schema.replication_applier_status_by_coordinator里的WORKERS_PROCESSED字段就会长期卡在 0。
- 直接查证命令:
SELECT WORKERS_PROCESSED, WORKERS_IDLE FROM performance_schema.replication_applier_status_by_coordinator\G - 若
WORKERS_PROCESSED无增长,说明 coordinator 没分发任务,问题一定出在主库或从库的依赖判断环节 - 常见根因:主库
binlog_row_image不是FULL,或表缺失主键/非空唯一键 → 写集为空 → 从库无法判断事务间是否冲突 → 全部塞给 coordinator 线程串行处理
binlog_transaction_dependency_tracking=COMMIT_ORDER 的隐形陷阱
MySQL 8.0 默认值是COMMIT_ORDER,但它只看主库事务的提交时间戳,不分析数据修改内容。一旦主库压力大、网络抖动或组提交被破坏,事务last_committed值就容易重复或错乱,结果就是从库不敢并行——宁可慢,也不乱。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 必须显式设为
WRITESET:SET GLOBAL binlog_transaction_dependency_tracking = 'WRITESET' - 配套必须开
transaction_write_set_extraction = 'XXHASH64'(默认值,但建议显式确认) -
WRITESET依赖主库提取每条变更的主键/唯一键哈希,所以binlog_row_image = FULL是硬门槛,漏掉这一条,WRITESET直接失效
slave_preserve_commit_order=ON 导致 worker 空转
这个参数本意是保 GTID 顺序,适合级联复制场景,但在纯读写分离从库上它是性能杀手。它强制 worker 线程按主库提交顺序“排队交卷”:哪怕事务 A 和 B 完全无关,B 也得等 A 的commit完成才能提交自己的结果。
- 查当前值:
SELECT @@slave_preserve_commit_order - 纯下游从库可安全关掉:
SET GLOBAL slave_preserve_commit_order = OFF - 关掉后,worker 线程不再互相等待,
WORKERS_IDLE会明显下降,WORKERS_PROCESSED上升更活跃 - 但注意:如果该从库还要作为中间节点转发 binlog 给下一级,必须保持
ON,否则下游报Error_code: 1594
DDL 语句让整个 MTS 队列“断流”
任何ALTER TABLE、CREATE INDEX等 DDL 在从库都是由 coordinator 线程独占执行的,且执行期间会阻塞所有 worker 线程——它们只能挂起状态,显示为Waiting for preceding transaction to commit。
- DDL 执行时,
SHOW PROCESSLIST里能看到大量 worker 线程卡在该状态 - DDL 越大(比如对千万级表加索引),阻塞越久,延迟雪球滚得越大
- 没有绕过办法,只能提前规避:用
ALGORITHM=INSTANT或ALGORITHM=INPLACE的 Online DDL;避免在高峰期执行;监控information_schema.INNODB_TRX里长事务,及时 kill 掉卡住的 DDL
真正生效的 MTS 不是靠堆线程数,而是靠主库能产出可并行的 writeset、从库能正确解析它、且没有 DDL 或保序逻辑人为掐断流水线。最容易被忽略的是主库binlog_row_image = FULL和表主键——这两项不达标,其他所有配置都白搭。

















