从库挂起与主库未提交事务无关,因复制仅同步已提交事件;真正原因多为数据不一致、锁冲突或redo日志瓶颈,应查last_sql_error、binlog出错事件及innodb log段状态。

主从复制中从库挂起,和“未提交事务”没有直接关系——INNODB_TRX里看到的 RUNNING 事务只存在于主库,从库根本不会继承这些事务状态;所谓“从库因未提交事务挂起”,实际是误判,真正卡住的是 SQL 线程在回放某条语句时被阻塞,根源往往在数据不一致、锁冲突或 Redo 日志瓶颈。
为什么从库不可能有主库的未提交事务
MySQL 复制只同步已 COMMIT 的 binlog 事件,未提交事务连 binlog 都不会写入,更不会发到从库。从库的 INNODB_TRX 表里查不到主库残留事务,SHOW ENGINE INNODB STATUS 也还原不出任何“未提交上下文”。常见误解是看到从库 SHOW PROCESSLIST 里有线程卡在 Waiting for preceding transaction to commit,就以为它在等主库某个没提交的事务——其实它是在等本机 MTS(多线程复制)调度器释放提交顺序锁,和主库事务生命周期完全无关。
从库挂起时该查什么而不是查事务
别在 information_schema.INNODB_TRX 上浪费时间。重点检查以下三项:
-
SHOW SLAVE STATUS\G中的Last_SQL_Error:比如Error_code: 1062(主键重复)、Error_code: 1032(记录不存在),说明是数据不一致触发的 SQL 线程中断 -
Relay_Master_Log_File和Exec_Master_Log_Pos对应的 binlog 位置,用mysqlbinlog --base64-output=decode-rows -v解析那条出错事件,确认是否含INSERT ... ON DUPLICATE KEY UPDATE或外部依赖逻辑 - 从库
SHOW ENGINE INNODB STATUS输出里的LOG段:关注Log sequence number与Log flushed up to差值,若超过innodb_log_file_size × 2,说明 Redo 日志空间吃紧,正在高频刷脏页,这是机械盘从库“假死”的典型征兆
遇到 Waiting for preceding transaction to commit 怎么办
这是 MySQL 5.7+ 启用 slave_preserve_commit_order = ON 后的正常调度行为,不代表故障,但可能放大底层瓶颈:
- 先确认是否真卡住:执行
SELECT COUNT(*) FROM performance_schema.replication_applier_status_by_worker;,如果所有 worker 的APPLYING_TRANSACTION字段长时间不变,再深入排查 - 临时缓解可关掉顺序保障:
SET GLOBAL slave_preserve_commit_order = OFF;,但仅限应急,关掉后可能引发从库 MVCC 可见性异常 - 根本解法是压降单事务粒度:避免主库批量
UPDATE跨千万行,拆成带LIMIT的循环;对大事务加/*+ MAX_EXECUTION_TIME(30000) */防止拖垮整个 MTS 队列
最容易被忽略的是:从库挂起很少由“事务”本身引起,更多是磁盘 IO、MDL 锁等待或 relay log 刷盘策略不当导致的连锁反应。盯住 Seconds_Behind_Master 是否持续增长、iostat -x 1 的 %util 是否打满、SELECT @@sync_relay_log; 是否为 0——这些比查事务列表管用十倍。











