能恢复,但必须立刻停写、确认日志状态、按删除类型选路径——等一小时再动手,90%的binlog或WAL就已轮转覆盖;DELETE已提交但有ROW格式binlog是最常见可控场景;TRUNCATE/DROP无备份则基本不可逆,仅能依赖从库、缓存或文件扫描等低成功率补救。

能恢复,但必须立刻停写、确认日志状态、按删除类型选路径——等一小时再动手,90%的 binlog 或 WAL 就已轮转覆盖。
DELETE 语句已提交,但有 ROW 格式 binlog
这是最常见也最可控的场景。关键不是“能不能”,而是“有没有在误删前的日志片段”。
- 先锁库:
FLUSH TABLES WITH READ LOCK(优先在从库操作,主库慎用) - 确认日志可用:
SHOW VARIABLES LIKE 'log_bin'必须为ON,SHOW VARIABLES LIKE 'binlog_format'必须为ROW - 定位时间点:用
mysqlbinlog --base64-output=decode-rows -v mysql-bin.000012 | grep -A 5 -B 5 "DELETE FROM orders"找到误删附近日志 - 生成反向 SQL:用
binlog2sql.py加--flashback参数,直接输出对应 INSERT;或手动截取:mysqlbinlog --stop-datetime="2026-08-10 14:22:59" mysql-bin.000012 | mysql -u root -p your_db
注意:--stop-datetime 必须设在误删执行完成前一秒,多 1 秒就可能包含 DELETE 本身。
TRUNCATE 或 DROP 表/库,且无备份
这类操作不记行级变更,binlog/WAL 里只有 DDL 语句,无法还原数据内容,只能靠外部副本或文件级抢救。
- 立刻检查是否有延迟从库:
SHOW SLAVE STATUS\G看Seconds_Behind_Master,若 > 0 且未同步误删语句,可直接从从库导出 - 查应用层缓存:Redis 是否存了近期全量快照?MQ 消息体是否含原始记录?ORM 的审计表(如
django_reversion)是否启用? - 物理文件扫描(仅限 MySQL InnoDB 且未重启):
undrop-for-innodb工具可尝试解析ibdata1,但成功率取决于后续写入量和 buffer pool 是否被刷出 - 云数据库(如阿里云 RDS)直接进控制台点「回溯实例」,选误删前时间点,5 分钟拉起只读库导出——这是唯一不依赖人工解析日志的兜底方案
别指望 ROLLBACK:TRUNCATE/DROP 是隐式提交,事务回滚无效。
SQL Server 在 FULL 恢复模式下误删
核心是“完整备份 + 日志链 + STOPAT”,缺一不可。简单说:没做过完整备份,日志备份再多也白搭。
- 先验证:
SELECT name, recovery_model_desc FROM sys.databases WHERE name = 'your_db',结果必须是FULL - 找最近一次完整备份:
RESTORE FILELISTONLY FROM DISK='full.bak'确认逻辑文件名 - 还原到临时库(避免影响生产):
RESTORE DATABASE your_db_temp FROM DISK='full.bak' WITH NORECOVERY, MOVE 'your_db' TO '/temp/your_db.mdf', MOVE 'your_db_log' TO '/temp/your_db.ldf' - 重放日志到误删前一秒:
RESTORE LOG your_db_temp FROM DISK='log_20260810.trn' WITH RECOVERY, STOPAT='2026-08-10 14:22:59' - 从临时库抽数据:
INSERT INTO your_db.dbo.orders SELECT * FROM your_db_temp.dbo.orders WHERE id IN (1001,1002),避免全表覆盖
注意:STOPAT 时间必须精确到秒,且日志备份链不能中断——中间缺失任意一个 .trn 文件,就只能退回到上一个完整备份点。
PostgreSQL WAL 归档开启但没做基础备份
WAL 本身不包含全量数据,只记录变更。没有 pg_basebackup 生成的基础备份,PITR 就像想用发票报销却没开发票一样——没起点,所有日志都无从锚定。
- 立即停止数据库:
pg_ctl stop -m fast,防止 checkpoint 刷脏页覆盖旧 WAL - 检查归档状态:
SHOW wal_level应为replica或logical,SHOW archive_mode应为on - 若无基础备份:只能尝试
pg_waldump手动解析最近几个 WAL 段,提取误删前的 INSERT/UPDATE,但需知道具体表 OID 和事务 ID,实操难度极高 - 若有基础备份:用
pg_basebackup拉起新集群,再配置recovery.conf(或postgresql.conf中的recovery_target_time)指向误删前时间点
最容易被忽略的是:WAL 归档脚本是否真正在运行?archive_command 返回 0 不代表成功,得去归档目录看文件是否真实生成并完整。

















