1032报错需定位binlog中read_master_log_pos对应位置,用mysqlbinlog解析并grep查找delete/update操作的where条件;确认主库存在后导出缺失行,set sql_log_bin=0导入从库;加主键是根本预防措施。

直接定位1032报错对应的binlog位置和操作条件
只看Last_Error: Can't find record in 'db.t'毫无用处。关键要从SHOW SLAVE STATUS\G里抓两个值:Master_Log_File(比如mysql-bin.000013)和Read_Master_Log_Pos(比如440267874)。注意不是Exec_Master_Log_Pos——它可能已滞后,会带你查错位置。
在主库执行:
mysqlbinlog --no-defaults -v -v --base64-output=DECODE-ROWS /var/lib/mysql/mysql-bin.000013 | grep -A 20 "end_log_pos 440267874"
输出中找以### DELETE FROM或### UPDATE开头的行,后面跟着类似WHERE @1=12345 AND @2='xxx'的内容——这就是从库缺失记录的完整定位条件。
-
@1通常对应表的第一列,但不绝对;必须用SHOW CREATE TABLE db.t确认字段顺序 - 如果表没主键,
@1~@N是整行字段镜像,WHERE条件极长,且对JSON空格、datetime毫秒等微小差异敏感 -
--base64-output=DECODE-ROWS必须加,否则看到的是BASE64编码,没法人工识别 - 若
grep无结果,说明该position不在当前binlog末尾附近,可扩大-A范围,或检查binlog是否已被rotate
确认主库是否存在、导出并补到从库
拿到WHERE @1=12345这类条件后,先在主库验证这行是否真实存在:
SELECT * FROM db.t WHERE id = 12345;
不存在就别往下做了——主库也丢了,得结合业务判断是否该恢复。
- 存在才继续:用
mysqldump --no-create-info --where="id=12345" db t > missing_row.sql导出 - 务必加
--skip-triggers,避免触发器干扰 - 传到从库后,导入前必须执行
SET SQL_LOG_BIN = 0(GTID模式下强制要求;非GTID下也建议加,防意外写入binlog) - 导入命令用
mysql db_name ,不能用<code>source——SQL_LOG_BIN = 0对source无效 - 表含TEXT/JSON字段时,
mysqldump默认不转义换行符,导入后肉眼难辨差异,必要时加--hex-blob
推进SQL线程并跳过错误事件
补完数据不等于复制自动恢复,SQL thread仍卡在原地。跳过方式取决于是否启用GTID:
- 非GTID模式:
STOP SLAVE; SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1; START SLAVE; - GTID模式:
STOP SLAVE;然后根据Retrieved_Gtid_Set末尾事务号生成空事务,例如:SET GTID_NEXT = '8f9e146f-0a18-11e7-810a-0050568833c8:4'; BEGIN; COMMIT; SET GTID_NEXT = 'AUTOMATIC';
- 跳过后立即
SHOW SLAVE STATUS\G确认Slave_SQL_Running: Yes且Seconds_Behind_Master开始下降
为什么加主键能根治1032反复发生
很多1032问题表面是数据缺失,深层原因是表没主键。MySQL ROW格式binlog依赖主键定位行;没主键时,只能靠全表扫描+所有字段值匹配,极易因字段值微小差异(如JSON空格、double精度、datetime毫秒)导致“主库有、从库找不到”。
更离谱的情况是:主库自己回放这条binlog都报1032——说明binlog本身就不可靠,不是从库的问题。
- 加主键后,
@1稳定指向主键列,WHERE条件变短、精准、抗干扰 - 主从执行逻辑一致,多线程复制(
slave_parallel_workers > 0)也不再因搜索算法(TABLE_SCAN,INDEX_SCAN)差异引发错位 - 加主键是成本最低、效果最彻底的预防手段,比每次手动修复快得多
真正麻烦的从来不是“怎么跳过”,而是“为什么又来了”——没主键的表,1032只是迟早的事。











