log-bin=mysql-binROW 模式(binlog_format=ROW),才會記錄逐行變更前後值mysqlbinlog 導出誤操作時間段的日志mysqlbinlog --no-defaults \
--start-datetime='2024-01-15 14:56:00' \
--stop-datetime='2024-01-15 14:57:00' \
-vv mysql-bin.000001 > /tmp/binlog_restore.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 */
### @8=-1 (4294967295) /* INT meta=0 nullable=1 is_null=0 */
| 類型 | Binlog 顯示 | INSERT 需轉換為 |
|---|---|---|
| DATETIME | @4=2012-10-25 00:00:00 | '2012-10-25 00:00:00'(加單引號) |
| 負數 INT | @8=-1 (4294967295) | -1(去除括號內無符號表示) |
| 字串含轉義 | @5='O\'Reilly' | 'O''Reilly'(單引號轉雙單引號) |
def read_binlog(file, column_num):
with open(file) as f:
last_table = None
for line in f:
if not line.startswith('###'): continue
parts = line.split(' ', 3)
if parts[1] == 'DELETE' and parts[2] == 'FROM':
parts[1] = 'INSERT'
parts[2] = 'INTO'
last_table = parts[3].strip()
elif parts[1].strip() == 'WHERE':
parts[1] = 'VALUES ('
# ... 依欄位號與類型做值轉換與拼接 ...
print(' '.join(parts))
完整腳本需處理:欄位計數判斷最後一欄加 );、NULL 值保持、字串轉義、負數清洗等細節。
python restore.py binlog_restore.txt 16 > restore.sql
mysql -u root -p test < restore.sql
16 為目標表總欄位數,腳本以此判斷何時結束一行 INSERT。
STATEMENT 或 MIXED 格式,無法逐行恢復,需改用備份+時間點恢復(PITR)。LOAD DATA 導入 CSV。掌握 Binlog 解析與 Row 事件反轉,是 DBA 從「會備份」進階到「會恢復」的關鍵技能。