SQL线程解析Relay Log中的binlog事件并按事务顺序重放,模拟主库执行上下文以确保行级一致;它不执行原始SQL字符串,不复现会话状态,ROW格式下依赖索引定位行,出错时需依GTID或位点精准修复。

SQL线程如何读取并执行Relay Log中的事件
SQL线程不是直接“执行SQL字符串”,而是解析relay log中序列化的binlog event,按事务粒度重放变更。它模拟主库的执行上下文(比如server_id、thread_id、事务隔离级别),但不复现连接会话状态(如临时表、用户变量)。关键点在于:它不关心原始SQL是否可重复,只确保行级结果与主库一致(尤其在ROW格式下)。
常见错误现象包括:Slave_SQL_Running: No、Seconds_Behind_Master持续增长、或SHOW SLAVE STATUS\G中显示Last_SQL_Error。典型原因有:从库缺失主库上已删的表、触发器/函数权限不足、DDL与DML冲突(如主库先DROP TABLE再INSERT INTO同名表)、或GTID_EXECUTED与relay log位置不匹配。
-
relay_log_info_repository = TABLE时,SQL线程每执行完一个事务就更新mysql.slave_relay_log_info表;设为FILE则写入relay-log.info文件——后者在崩溃恢复时可能丢失最后几条事务 - MySQL 5.7+默认启用
slave_parallel_type = LOGICAL_CLOCK,此时SQL线程退化为协调器,实际由worker线程并发执行;但遇到DDL或跨库事务时仍会降级为单线程串行 - 若relay log中含
CREATE TEMPORARY TABLE,SQL线程会跳过该event(从库不支持复制临时表),但不会报错——这点容易被忽略,导致应用逻辑异常
为什么SQL线程重放可能比主库慢,且无法完全避免延迟
SQL线程本质是单线程串行消费者(即使启用了并行复制,也受限于事务依赖图和slave_preserve_commit_order开关)。它必须严格按relay log中事务的提交顺序执行,不能乱序——否则会破坏一致性语义。而主库的写入是并发的,多个事务可能同时落盘到binlog。
性能瓶颈常出现在:大事务(如UPDATE百万行)、全表扫描类DDL(ALTER TABLE ... ALGORITHM=COPY)、或从库I/O能力弱于主库(relay log写入慢 → SQL线程无事可做)。
- 检查
SHOW PROCESSLIST中SQL线程状态:若长期处于Waiting for dependent transaction to commit,说明并行复制被阻塞;若卡在Updating或Writing to net,大概率是慢查询或锁等待 -
innodb_flush_log_at_trx_commit = 1在从库开启会加重刷盘压力,但关闭(设为2或0)可能在崩溃时丢失已重放但未刷盘的事务 - 使用
ROW格式时,SQL线程需解析每行变更并定位目标行(走索引或全表扫描),若从库缺失对应索引,性能断崖式下降
SQL线程出错后如何安全跳过或修复relay log执行点
跳过错误不能靠盲目执行SET GLOBAL sql_slave_skip_counter = 1(仅对STATEMENT格式有效,且MySQL 8.0.23+已弃用)。正确做法取决于复制模式:
- GTID模式下,用
STOP SLAVE; SET GTID_NEXT = 'xxx-yyy-zzz:N'; BEGIN; COMMIT; SET GTID_NEXT = 'AUTOMATIC'; START SLAVE;注入空事务覆盖错误位置 - 基于位置的复制,先确认
Relay_Master_Log_File和Exec_Master_Log_Pos,再用CHANGE MASTER TO ... RELAY_LOG_FILE='xxx', RELAY_LOG_POS=yyy手动调整(风险高,需确保relay log未被轮转) - 若错误源于数据不一致(如主从某行值不同),优先用
pt-table-checksum校验,再用pt-table-sync修复,而非跳过
最易被忽略的一点:SQL线程重放时不会校验主键/唯一键冲突是否由自身引起。例如主库因应用双写产生重复主键,该冲突会被原样带到从库,导致SQL线程中断——此时问题根源在主库写入逻辑,而非复制配置本身。


















