必须确认log_bin=on且binlog_format=row,否则无法获取被删行内容;需检查binlog_row_image=full、日志未过期,并用mysqlbinlog -v --base64-output=decode-rows解析delete_rows_event,取其所在事务的end_log_pos为回滚锚点,禁用外键后使用my2sql等工具生成安全insert。

确认binlog_format=ROW且log_bin=ON是前提
如果 SHOW VARIABLES LIKE 'log_bin' 返回 OFF,或 binlog_format 不是 ROW,那根本找不到被删的行内容——STATEMENT 格式下 DELETE FROM t 只记语句,不存任何字段值。这不是“定位不准”,而是压根没记录。
还要顺手查一下:SHOW VARIABLES LIKE 'binlog_row_image' 最好是 FULL;SHOW BINARY LOGS 确认目标时间段的日志文件还在磁盘上,没被 PURGE 或过期清理掉。
用mysqlbinlog -v 解析并人工筛选 DELETE_ROWS_EVENT
别指望 grep "DELETE FROM" 能准确定位事务——ROW 格式里没有这种文本 SQL,只有二进制事件。必须加 --base64-output=DECODE-ROWS -v 才能看到实际字段值(形如 ### @1=123 ### @2='abc')。
关键动作是盯住 DELETE_ROWS_EVENT,它会明确标注库名、表名和每条被删记录的完整镜像。注意三点:
- 每个事务以
BEGIN开头、COMMIT结尾,DELETE_ROWS_EVENT一定落在这个区间内 - 往上翻几行,看紧邻的
GTID_LOG_EVENT或QUERY_EVENT,可能含执行线程 ID 和时间戳(但不保证有用户名) - 服务器时区可能和本地不一致,先查
SELECT NOW()对齐时间,再用--start-datetime缩小范围
记下 end_log_pos 是后续回滚的关键锚点
DELETE_ROWS_EVENT 结尾处的 end_log_pos 值(比如 1234567)不是可有可无的元数据,它是整个事务的结束位置,也是你后续用 my2sql 或手动构造回滚 SQL 的截止坐标。
常见错误是只记了 at 位置(即事件起始偏移),结果切出来的片段漏掉事务中其他关联变更(比如同一事务里先 UPDATE 再 DELETE)。正确做法是:找到该 DELETE_ROWS_EVENT 所在的 BEGIN...COMMIT 区间,取整个区间的 end_log_pos 作为停止点。
命令示例(带时间过滤+解码):
mysqlbinlog --base64-output=DECODE-ROWS -v \ --start-datetime="2026-09-03 15:20:00" \ --stop-datetime="2026-09-03 15:25:00" \ /var/lib/mysql/mysql-bin.000042
别跳过事务边界直接拼 INSERT
从 DELETE_ROWS_EVENT 里抄出字段值手动写 INSERT 很危险:容易漏掉 TIMESTAMP 默认值、JSON 字段转义、NULL 与空字符串混淆,更别说自增主键冲突或外键约束报错。
真正能落地的方案是用工具把整段事务反向生成 SQL,例如 my2sql ——它能自动识别 DELETE_ROWS_EVENT 并输出带完整 WHERE 条件的可执行 INSERT,还能处理字符集、类型映射和注释清洗。
最容易被忽略的一点:执行前必须禁用外键检查(SET FOREIGN_KEY_CHECKS=0),并确保目标库字符集与原库一致,否则中文字段可能乱码或截断。










