DELETE 如何秒級恢復?備份恢復需重放 Binlog,耗時不可控。**前提:binlog_format=ROW**,否則無法從 Binlog 解析出具體行數據,只能走備份恢復。
mysqlbinlog 導出指定時間區間 BinlogDELETE 反轉為 INSERTmysqlbinlog --no-defaults \ --start-datetime='2012-12-25 14:56:00' \ --stop-datetime='2012-12-25 14:57:00' \ -vv mysql-bin.000001 > /home/zhoujy/restore/binlog.txt
-vv 關鍵:將 ROW 事件解碼為可讀的偽 SQL 格式。
### DELETE FROM test.me_info ### WHERE ### @1=2165974 /* INT meta=0 nullable=0 is_null=0 */ ### @2='1984:03:17' /* DATE meta=0 nullable=1 is_null=0 */ ### @3=NULL /* DATE meta=765 nullable=1 is_null=1 */ ### @4=2012-10-25 00:00:00 /* DATETIME meta=0 nullable=0 is_null=0 */ ### @5='' /* VARSTRING(765) meta=765 nullable=1 is_null=0 */ ### @6=0 /* TINYINT meta=0 nullable=1 is_null=0 */ ### @7='' /* VARSTRING(765) meta=765 nullable=1 is_null=0 */ ### @8=-1 (4294967295) /* INT meta=0 nullable=1 is_null=0 */ ### @9=0 /* MEDIUMINT meta=0 nullable=1 is_null=0 */ ...(共 36 列)
| 類型 | Binlog 格式 | 目標 INSERT 格式 |
|---|---|---|
| DATETIME | @4=2012-10-25 00:00:00 | '2012-10-25 00:00:00' |
| 負數 INT | @8=-1 (4294967295) | -1(去掉括號內無符號補碼) |
| 字符串轉義 | 'O\'Reilly' | 'O\\'Reilly'(雙重轉義) |
restore.py#!/bin/env python
# -*- encoding: utf-8 -*-
# restore.py: 通過 Binlog 恢復 DELETE 誤操作數據
# Author: zhoujy
import sys
def read_binlog(file, column_num):
f = open(file)
num = '@' + str(column_num)
while True:
line = f.readline()
if not line:
break
if line.strip()[:3] != '###':
continue
parts = line.split(' ', 3)
# DELETE FROM -> INSERT INTO
if parts[1] == 'DELETE' and parts[2] == 'FROM':
parts[1] = 'INSERT'
parts[2] = 'INTO'
parts[3] = parts[3].strip()
# WHERE -> VALUES (
if parts[1].strip() == 'WHERE':
parts[1] = 'VALUES ('
# 處理列值
if '@' in ''.join(parts):
col_name = parts[3].split('=', 1)[0]
val = parts[3].split('=', 1)[1].strip()
# 去除類型註釋 /* ... */
val = val.split('/*')[0].strip()
# 字符串處理:去首尾引號、轉義單引號、反斜杠
if val.startswith("'") and val.endswith("'"):
val = val[1:-1].replace('\\', '').replace("'", "\\'")
val = "'" + val + "'"
# 負數處理:去掉 (4294967295)
elif ' ' in val and val.split()[1].startswith('('):
val = val.split()[0]
# NULL 處理
elif val == 'NULL':
pass
# 判斷是否最後一列
if col_name == num:
val += ');'
else:
val += ','
parts[3] = val
print(' '.join(parts[1:]))
if __name__ == '__main__':
read_binlog(sys.argv[1], sys.argv[2])
# column_num=36 表示表有 36 個列 python restore.py binlog.txt 36 > binlog.sql # 檢查生成的 SQL head -5 binlog.sql # INSERT INTO test.me_info VALUES (2123269, '1990:11:12', NULL, 2, '', 0, '', -1, 0, 340800, 1, 0, '', ..., 1, NULL); # 回放恢復 mysql test < binlog.sql
--start/stop-datetime 縮小範圍,避免解析無關事件。source。### UPDATE 事件,提取 SET 子句與 WHERE 子句(前後映射)。flashback 類開源項目(如 mysqlbinlog-flashback),功能更完善。掌握 mysqlbinlog -vv 解析 ROW 事件格式,編寫針對性轉換腳本,能在**分鐘級恢復誤刪數據**,是 DBA 應急工具箱裡的利器。核心在于**細節處理**:DATETIME 加引號、負數去括號、字符串雙重轉義。