必须启用WRITESET:主库设binlog_transaction_dependency_tracking=WRITESET、binlog_format=ROW且表有主键/唯一键,从库设slave_parallel_type=LOGICAL_CLOCK、slave_parallel_workers>0;COMMIT_ORDER仅依赖提交时间窗口,不检测行级冲突,OLTP下并行度极低。

MySQL 8.0 默认的并行复制几乎不并行,必须显式启用 WRITESET 才能真正压榨 slave_parallel_workers 的并发能力;否则即使设成 16,实际活跃线程可能长期只有 1–2 个。
为什么 COMMIT_ORDER 在 OLTP 场景下基本失效
它只看事务提交时间窗口是否重叠,完全不检查“改了哪几行”。同一个连接里连续执行 UPDATE users SET name='a' WHERE id=1 和 UPDATE orders SET status=2 WHERE user_id=1,会被强制串行——哪怕两表无关联、无锁竞争。现象是 SHOW SLAVE STATUS\G 中 Slave_SQL_Running_State 长期卡在 Waiting for preceding transaction to commit,且 performance_schema.replication_applier_status_by_coordinator 里 WORKERS_WAITING 明显高于 WORKERS_PROCESSED。
更关键的是:MySQL 8.0.27+ 默认开启 replica_preserve_commit_order = ON,这会进一步把 WRITESET 退化回 COMMIT_ORDER 行为,除非你主动关掉它(但关掉有数据一致性风险,见文末)。
启用 WRITESET 的三要素缺一不可
主库必须同时满足以下条件,从库才能真正按行级冲突做并行判断:
-
binlog_transaction_dependency_tracking = WRITESET(需SET PERSIST或写入my.cnf的[mysqld]段) -
binlog_format = ROW(STATEMENT或MIXED下 WRITESET 不生效) - 所有被修改的表必须有
PRIMARY KEY或UNIQUE KEY(否则事务自动降级为COMMIT_ORDER,且不会报错,只会静默退化)
从库无需额外配置 WRITESET 参数,但必须确保 slave_parallel_type = LOGICAL_CLOCK(8.0 默认已是),且 slave_parallel_workers > 0。
WRITESET_SESSION 是什么?什么时候该用它
它是 WRITESET 的保守变体:同一会话内事务仍强制串行,仅跨会话事务才按 writeset 并行。适用场景极少,比如你明确知道某类长事务(如报表导出)总在一个连接里批量执行,又不想让它阻塞其他连接的更新——此时可设为 WRITESET_SESSION 来保底串行性。
但绝大多数 OLTP 场景应坚持用纯 WRITESET。注意:WRITESET_SESSION 同样依赖唯一键,且不解决单会话内高延迟问题。
最容易被忽略的致命细节
WRITESET 依赖 transaction_write_set_extraction = XXHASH64(8.0 默认值),但如果你用的是 Group Replication,还必须禁用 MyISAM 等非事务引擎(disabled_storage_engines="MyISAM,BLACKHOLE,...")。最隐蔽的坑是:表缺失唯一键时,MySQL 不报错、不警告,只是悄悄退化——你得查 performance_schema.replication_applier_status_by_worker 的 LAST_ERROR_MESSAGE,或观察 Writesets_used 字段是否持续为 0。


















