必须定位缺失行并补入:从SHOW SLAVE STATUS获取Master_Log_File和Read_Master_Log_Pos,用mysqlbinlog解析对应位置找到DELETE/UPDATE的WHERE条件,验证主库存在后导出补入从库,再SET GLOBAL SQL_SLAVE_SKIP_COUNTER=1跳过错误。

Last_Error里出现 Can't find record in 't',说明从库执行 UPDATE 或 DELETE 时根本查不到那行数据。这不是“跳过就能好”的小毛病,而是数据不一致的明确信号——必须定位缺失行、补上它,再推进复制,否则下一次同条件更新还会卡住。
怎么从 Last_Error 定位到具体哪条记录丢了
Last_Error 只告诉你“找不到”,不告诉你“找什么”。关键字段在 SHOW SLAVE STATUS\G 输出里:
-
Master_Log_File和Read_Master_Log_Pos(不是Exec_Master_Log_Pos)——这是出错事务在主库 binlog 中的精确坐标 - 用这个坐标去主库解析 binlog:
mysqlbinlog --no-defaults -v -v --base64-output=DECODE-ROWS /var/lib/mysql/<code>Master_Log_File| grep -A 20 "end_log_posRead_Master_Log_Pos" - 输出里找
### DELETE FROM `db`.`t` WHERE @1=12345 AND @2='xxx'这类行——@1、@2对应表字段顺序,就是缺失记录的完整 WHERE 条件 - 如果
grep没结果,要么-A范围太小,要么 binlog 已 rotate,得结合SHOW VARIABLES LIKE 'datadir'确认真实路径再试
确认主库有、从库真缺,再导出补入
拿到WHERE 条件后,先验证主库是否存在:
- 在主库执行:
SELECT * FROM db.t WHERE id = 12345;(把@1=12345转成实际字段名) - 存在才继续;不存在说明主库也丢了,得回溯业务操作,不能硬补
- 导出这行:
mysqldump --no-create-info --skip-triggers --where="id=12345" db t > missing_row.sql - 传到从库执行前,必须加
SET SQL_LOG_BIN = 0;(GTID 模式下强制要求,否则 INSERT 又被同步回去,死循环) - 别用
INSERT ... SELECT直插,网络中断会导致半截数据
补完数据后怎么让复制真正跑起来
补数据 ≠ 复制自动恢复。SQL thread 还卡在原地:- 执行:
STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; START SLAVE; - 检查
Slave_SQL_Running: Yes且Seconds_Behind_Master开始下降才算成功 - 如果仍报 1032,说明还有别的行缺失——不是单点问题,得用
pt-table-checksum全量校验 - 别忽略
sql_log_bin=0的历史导入:这类缺失往往集中在某几张表,补完后建议查主库 binlog 或操作日志确认是否批量漏同步
为什么无主键表特别容易触发 1032
RBR 模式下,MySQL 靠主键或唯一键精确定位行。没主键时:- 退化为全表扫描匹配所有字段,主从任意字段值有微小差异(比如
DATETIME精度、JSON 字段换行符)就会失败 - 并行复制(MTS)下更危险:多个 worker 并发执行,Hash 冲突导致同一事务被不同 worker 乱序应用
- 查表有没有主键:
SELECT TABLE_SCHEMA,TABLE_NAME FROM information_schema.TABLE_CONSTRAINTS WHERE CONSTRAINT_TYPE='PRIMARY KEY' AND TABLE_SCHEMA='db' AND TABLE_NAME='t';返回空就确认缺失 - 临时方案是加自增主键:
ALTER TABLE t ADD COLUMN id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST;,但要注意业务是否依赖原有主键逻辑
真正麻烦的不是定位和补数据,而是那些没有主键、又长期开着 sql_log_bin=0 导入的表——它们像定时炸弹,直到第一次 UPDATE 才爆。补完一行,可能还有几百行等着你。


















