SQL线程不走标准SQL执行器,因需严格还原主库已提交变更,必须绕过优化器、权限校验、触发器、外键检查等环节,直接调用存储引擎底层接口写入数据,避免NOW()等上下文函数重求值导致不一致。

SQL线程为什么不用InnoDB的事务执行器直接重放?
因为从库的SQL线程不是在“执行新业务逻辑”,而是在“严格还原主库已提交的变更”。它必须绕过优化器、权限校验、触发器、外键约束检查等运行时环节,否则可能因环境差异(如函数返回值、临时表、会话变量)导致重放失败或数据不一致。
-
SQL线程解析的是中继日志(relay log)里的事件,这些事件来自主库binlog,本质是“已确认成功”的操作快照,不是原始SQL文本(尤其在ROW格式下根本没SQL) - 它调用的是存储引擎层的底层写接口(如
ha_innobase::write_row()),跳过SQL层的parse → optimize → execute全链路 - 如果走标准SQL执行器,
NOW()、UUID()、@var等上下文相关值会在从库重新求值,破坏一致性——这正是STATEMENT格式被弃用的核心原因
ROW格式下SQL线程到底在做什么?
它不“执行SQL”,而是按binlog_format=ROW记录的行镜像(before_image / after_image)直接修改数据页。比如主库某行name='张三'被更新为'李四',SQL线程就定位到该行物理位置,把对应字段字节覆盖掉。
- 不解析WHERE条件,不走索引查找逻辑,靠
primary key或unique key快速定位(若无则全表扫描匹配) - 不触发
BEFORE/AFTER UPDATE触发器——触发器是业务逻辑,不属于数据状态变更本身 - 不校验外键约束(除非显式开启
foreign_key_checks=ON,但生产环境通常关闭以保重放速度)
为什么不能让多个SQL线程并行回放?
MySQL 5.6引入了slave_parallel_workers,但并行粒度受限于“事务间依赖关系”。真正能安全并行的,不是任意SQL,而是满足LOGICAL_CLOCK或WRITESET分组条件的事务组。
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
- 单个事务内部的SQL必须串行:UPDATE A; UPDATE B; DELETE C 必须保持顺序,否则违反原子性
- 跨事务并行的前提是它们修改的是不同库/表/行集,且没有GTID依赖链;否则
SQL线程会退化为单线程回放 - 启用
binlog_transaction_dependency_tracking=WRITESET后,MySQL会基于行级写集计算事务独立性,这是5.7.22+高并发从库低延迟的关键
最容易被忽略的细节:SQL线程的错误恢复行为
当SQL线程遇到错误(如主键冲突、字段类型不匹配、表结构不一致),默认会停止复制(Slave_SQL_Running: No)。它不会自动跳过或重试,也不会回滚已执行的部分——因为中继日志是追加写入的,没有“事务边界”封装。
- 手动跳过需用
SET GLOBAL sql_slave_skip_counter = 1(仅适用于STATEMENT)或mysqlbinlog --skip-gtids+mysql重放修复 - 更安全的做法是:先停复制 → 检查
SHOW SLAVE STATUS\G中的Exec_Master_Log_Pos和Relay_Log_File→ 定位出错事件 → 人工确认是否可跳过 → 再启复制 - 一旦跳过,后续所有GTID都会被标记为“已执行”,无法再通过
GTID_PURGED清理——这个副作用常被低估










