我可以回滚我已经提交的交易吗? (数据丢失)

时间:2012-09-18 07:29:27

标签: database postgresql data-recovery

我提交了一个不正确的UPDATE声明并丢失了一些数据。

在我已经提交之后,现在可以回滚吗?

任何帮助?

ROLLBACK

NOTICE: there is no transaction in progress

1 个答案:

答案 0 :(得分:86)

不,您无法撤消,回滚或撤消提交。

停止数据库!

(注意:如果您从文件系统中删除了数据目录,请不要停止数据库。以下建议适用于DELETE或类似的意外提交,而不是rm -rf /data/directory方案。

如果此数据很重要,现在停止您的数据库并且不要重新启动它。使用pg_ctl stop -m immediate以便在关闭时不运行检查点。

提交后,您无法回滚事务。您需要从备份中恢复数据,或使用point-in-time recovery,必须在事故发生前设置

如果您没有设置任何PITR / WAL归档并且没有备份,那么您将遇到麻烦。

紧急缓解

数据库停止后,您应该创建整个数据目录的文件系统级别 - 包含basepg_clog等的文件夹。复制所有数据到一个新的位置。不要对新位置的副本执行任何操作,如果您没有备份,则唯一希望恢复数据。如果可以,请在某些可移动存储上制作另一个副本,然后从计算机上拔下该存储。请记住,您需要绝对数据目录的每个部分,包括pg_xlog等。没有任何部分是不重要的。

究竟如何制作副本取决于您正在运行的操作系统。数据目录取决于您正在运行的操作系统以及如何安装PostgreSQL。

某些数据可以幸存下来

如果你足够快地停止你的数据库,你可能希望从表中恢复一些数据。那是因为PostgreSQL使用multi-version concurrency control (MVCC)来管理对其存储的并发访问。有时,它会将您更新的行的新版本写入表中,保留旧版本但标记为“已删除”。稍后autovaccum出现并将行标记为可用空间,以便稍后INSERTUPDATE覆盖这些行。因此,UPDATE d行的旧版本可能仍然存在,存在但无法访问。

此外,Pg分两个阶段写作。第一个数据被写入预写日志(WAL)。只有一旦它被写入WAL并命中磁盘,它就会被复制到“堆”(主表),可能会覆盖那里的旧数据。 WAL内容由bgwriter和定期检查点复制到主堆。默认情况下,检查点每5分钟发生一次。如果您设法在检查点发生之前停止数据库并通过硬杀死它,拔出计算机上的插头或在pg_ctl模式下使用immediate来停止数据库,那么您可能已经从在检查点发生之前,您的旧数据更可能仍然在堆中。

现在您已经完成了数据目录的完整文件系统级副本,如果您确实需要,可以备份数据库;数据仍然会消失,但你已经做了尽可能给自己一些希望恢复它的希望。鉴于选择,我可能会将数据库关闭以保证安全。

恢复

您现在可能需要hire an expert in PostgreSQL's innards来帮助您进行数据恢复尝试。准备好支付专业人员的时间,可能需要相当多的时间。

我在Pg邮件列表上发布了这个帖子,Виктор Егоров linked to depesz's post on pg_dirtyread,看起来就像你想要的那样,虽然它没有恢复TOAST ed数据所以它有限效用。尝试一下,如果你很幸运,它可能会起作用。

请参阅:pg_dirtyread on GitHub

我已删除了我在本节中所写的内容,因为该工具已将其废弃。

另见PostgreSQL row storage fundamentals

预防

请参阅我的博客文章Preventing PostgreSQL database corruption


在半相关的旁注上,如果你使用two phase commit,你可以ROLLBACK PREPARED进行为提交准备但未完全提交的转换。这是你回滚已经提交的交易的最接近的,并不适用于你的情况。