PostgreSQL 数据误删后的紧急止损:原理与代码实战

· 代码经验

在日常管理数据库的时候,最让人紧张的情况就是不小心把数据删掉了——比如执行 DELETE 语句时忘了加 WHERE 条件,或者手滑运行了 TRUNCATE,甚至一不小心把整张表用 DROP TABLE 给删了,这些操作都可能让系统服务中断,也可能导致用户的数据彻底找不回来。

不过好在 PostgreSQL 提供了不少办法来应对这种意外,关键是要动作快、方法对

这篇文章会介绍三种常见的恢复手段,并以可以直接运行的代码为主,帮助你在出问题后尽快把数据救回来。

一、用事务回滚(适合还没提交的删除)

如果你是在一个事务里删的数据,而且还没有提交,这种情况最容易处理:

-- 开始一个事务
BEGIN;

-- 错误地删了数据(举个例子)
DELETE FROM users WHERE created_at < '2025-01-01';

-- 发现错了!马上回滚
ROLLBACK;

-- 检查数据是不是还在
SELECT COUNT(*) FROM users;
⚠️ 注意:只要执行了 COMMIT,这个办法就不管用了。

二、用时间点恢复(PITR)——生产环境最稳的办法

前提是你已经打开了 WAL 日志归档功能,并且有定期做的完整备份。

第一步:改配置文件(postgresql.conf)

wal_level = replica
archive_mode = on
archive_command = 'cp %p /var/lib/postgresql/wal_archive/%f'

改完之后需要重启 PostgreSQL 才能生效。

第二步:做一次完整的备份

# 用 pg_basebackup 命令
pg_basebackup -D /backup/base_$(date +%Y%m%d) -Ft -z -P -U postgres

第三步:模拟误删,并记下准确的时间

-- 假设在 2026-04-08 16:30:00 删错了
DELETE FROM orders WHERE status = 'pending';
COMMIT;

第四步:开始恢复操作

  1. 先停掉 PostgreSQL 服务
  2. 清空当前的数据目录(但要保留 pg_wal 这个文件夹)
  3. 把之前备份的内容复制回数据目录
  4. 在数据目录里新建一个空文件,名字叫 recovery.signal
  5. 编辑 postgresql.auto.conf 文件,加上下面这两行配置:
restore_command = 'cp /var/lib/postgresql/wal_archive/%f %p'
recovery_target_time = '2026-04-08 16:29:50'
  1. 启动数据库,系统会自动把日志重放到指定时间点之前,数据就恢复好了。

三、从 WAL 日志里找回数据(没有备份时的最后办法)

如果你没开 PITR 功能,但 WAL 日志文件还在(比如还没被 VACUUM 清理掉),可以用像 walminer 这样的工具尝试恢复:

安装 walminer(需要自己编译)

git clone https://github.com/ChristophBerg/walminer.git
cd walminer
make && make install

解析日志,生成还原用的 SQL 语句

-- 加载扩展
CREATE EXTENSION walminer;

-- 告诉工具要分析哪个 WAL 文件
SELECT walminer_wal_add('/var/lib/postgresql/16/main/pg_wal/0000000100000000000000A1');

-- 查看某段时间里对 orders 表的 DELETE 操作(假设表 OID 是 16384)
SELECT * FROM walminer_change(
    '2026-04-08 16:25:00',
    '2026-04-08 16:35:00',
    'public.orders',
    'DELETE'
);

-- 工具可能会输出像这样的 INSERT 语句
-- INSERT INTO orders VALUES (1001, 'pending', '2026-04-01');
-- INSERT INTO orders VALUES (1002, 'pending', '2026-04-02');

把这些 INSERT 语句在数据库里执行一遍,就能把之前删掉的数据重新加回去。

建议和总结

用上面这三种方法,大多数因为手误造成的数据丢失都能成功恢复。记住:别慌张,快速判断情况,恢复完一定要检查结果,这才是面对问题时最重要的做法。