writeset通过计算事务修改行的主键或唯一键哈希值(write_set)并写入binlog,从库据此判断并行性:只要两事务write_set无交集(如分别更新user_id=100和200),即视为无冲突可并发回放,实现行级细粒度并行。

WRITESET 并行度更高,因为它不依赖主库是否“凑成组”,而是直接看事务改了哪些具体行。
WRITESET 怎么判断事务能不能并行?
它在事务提交前,计算所有被修改行的主键或唯一键哈希值(write_set),存进 binlog。从库拿到后,只要两个事务的 write_set 没交集(比如一个改 user_id=100,另一个改 user_id=200),就认为可并行回放。
- 不需要主库有高并发、也不需要事务刚好落在同一组提交里
- 哪怕两个事务相隔几秒、来自不同连接,只要没改同一行,就能被 worker 并发调度
- 本质是行级冲突检测,粒度比 LOGICAL_CLOCK 更细
LOGICAL_CLOCK 为什么容易卡住?
它靠主库的 last_committed 值分组——这个值只在事务“组提交”时才复用。一旦主库写入不够密集(比如定时任务单线程批量更新),last_committed 就变成单调递增,所有事务都被当成串行依赖链。
- 现象:从库
Slave_SQL_Running_State长时间停在 “Waiting for an event from Coordinator” - 即使事务之间毫无关系(比如分别更新
orders和logs表),只要没进同一组,就无法并行 -
binlog_group_commit_sync_delay等参数调得再细,也救不了低峰期或单线程写场景
WRITESET 的生效条件非常严格,漏一个就退化为单线程
它不是“开了 slave_parallel_workers 就自动生效”的功能,必须主从协同配置:
- 主库必须设
binlog_transaction_dependency_tracking = WRITESET(否则 binlog 里压根没write_set数据) - 主库必须保持
binlog_row_image = FULL(否则无法准确提取被改行的唯一键) - 从库设
slave_parallel_type = LOGICAL_CLOCK(注意:名字没变,但 8.0+ 实际支持 write_set 调度) - 从库
slave_preserve_commit_order = 1推荐开启(避免因并行导致从库提交顺序乱序引发一致性问题)
WRITESET 在什么情况下会失效?
它快,但不是万能的。业务写模式决定它能不能真正跑起来:
- 表没有主键或唯一索引 →
write_set提取失败,退化为 COMMIT_ORDER 模式(等效单线程) - 大量更新同一张热点表的同一主键范围(如订单号连续)→
write_set哈希碰撞高,并行度骤降 - 大事务(比如一次更新 50 万行)→ 它会阻塞后续所有依赖该表 write_set 的事务,反而拉长延迟
- 用了
WRITESET_SESSION模式 → 同一连接内事务强制保序,牺牲并行换一致性
真正起效的关键,不在从库开了几个 worker,而在于主库有没有把足够干净、可区分的 write_set 写进 binlog —— 这点最容易被忽略,也是线上调优时第一轮就要验证的。











