大事务直接卡死从库回放,因其在主库生成巨量binlog event后,从库SQL线程必须串行完整执行该事务才能推进位点,期间后续binlog全部积压在relay log中不动,Seconds_Behind_Master停滞上涨,且即使开启MTS也无法并行——因未拆分的大事务仍被当作原子单元分配给单个worker。

大事务为什么直接卡死从库回放
主库一个大事务(比如 UPDATE orders SET status = 'archived' WHERE create_time )在主库可能 20 秒就提交了,但它的 binlog 是“原子写入”的:整个事务的所有变更被打包进一段连续的 binlog event 流。从库 SQL 线程必须按序、完整地重放这一整段——不能跳过、不能并行、不能拆解。
哪怕你开了 slave_parallel_workers=4,只要这个事务本身没打上组提交(last_committed 相同),它仍会被当作单个不可分割单元,强制由一个 worker 执行到底。结果就是:其他小事务全在队列里干等,延迟秒数直接飙升到和主库执行时间持平甚至更高(因从库硬件弱、IO 慢)。
Seconds_Behind_Master 为什么这时候会“失真”
Seconds_Behind_Master 的计算逻辑是:(T2 - T1) + (T3 - T2),即“网络传输耗时 + 回放耗时”。但当大事务正在回放中,T3 还没到达,这个值只反映“已接收日志中最老事件”与“当前已执行事件”的时间差,而非最新事务的延迟。更关键的是:
- 如果 SQL 线程卡在某个大事务中间(比如正扫表更新第 80 万行),
Seconds_Behind_Master会持续上涨,但监控采样可能只看到“峰值后回落”,错过真实阻塞点 - 一旦该事务回放完成,数值瞬间归零,给人“问题自愈”的错觉,其实只是积压被清空了一次
- 它完全不体现“正在执行的事务有多慢”,只反映“已排队日志的等待时间”
如何快速定位是不是大事务惹的祸
别等业务报警才查。主库上盯两个信号:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 执行
SHOW MASTER LOGS;,连续几次对比File_size,1 分钟内增长超 100MB 就高度可疑 - 查最近 5 分钟生成的 binlog 文件(如
mysql-bin.000012),用mysqlbinlog --base64-output=decode-rows -v mysql-bin.000012 | grep -A 5 -B 5 "COMMIT"看 COMMIT 前的事件密度;密集出现长 UPDATE/DELETE 就是证据 - 从库执行
SHOW PROCESSLIST;,如果看到State: updating或executing持续超过 10 秒,且Info字段显示大范围 WHERE 条件,基本坐实
拆分事务时最容易踩的坑
很多人改写成循环分页更新,却忽略两个致命细节:
- 没加
LIMIT的子句:比如UPDATE ... WHERE id BETWEEN ? AND ?但没限制每次最多改 1000 行,万一区间内数据暴增,又变大事务 - 没控制事务粒度:把 10 万行拆成 100 个事务,但每个事务里塞了 1000 行 + 复杂子查询 + 触发器,实际每事务仍要 5 秒,总延迟反而更碎更难排查
- 漏掉唯一索引或主键:若表无主键,从库回放时对每条
UPDATE都要全表扫描找目标行,1000 行 × 全表扫描 = 延迟翻倍
真正有效的拆分,是让每个子事务都能在 200ms 内提交,并确保 WHERE 条件能命中索引——否则只是把“一颗炸弹”换成“一串哑弹”。










