59

我提交了不正确的UPDATE陈述并丢失了一些数据。

在我已经承诺之后,现在可以回滚吗?

有什么帮助吗?

ROLLBACK

NOTICE: there is no transaction in progress

4

1 回答 1

116

不,您不能撤消、回滚或撤消提交。

停止数据库!

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

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

事务一旦提交就不能回滚。您将需要从备份中恢复数据,或使用时间点恢复,这必须在事故发生之前进行设置。

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

紧急缓解

一旦您的数据库停止,您应该制作整个数据目录的文件系统级副本 - 包含base,pg_clog等的文件夹。将其全部复制到新位置。不要对新位置的副本做任何事情,如果您没有备份,这是您恢复数据的唯一希望。如果可以的话,在某个可移动存储上制作另一个副本,然后从计算机上拔下该存储。请记住,您绝对需要数据目录的每个部分,包括pg_xlog等。没有部分是不重要的。

具体如何制作副本取决于您运行的操作系统。数据目录的位置取决于您运行的操作系统以及安装 PostgreSQL 的方式。

一些数据可能存在的方式

如果您足够快地停止数据库,您可能希望从表中恢复一些数据。这是因为 PostgreSQL 使用多版本并发控制 (MVCC)来管理对其存储的并发访问。有时它会将您更新的行的新版本写入表中,将旧版本留在原处但标记为“已删除”。过了一会儿,autovaccum出现并将行标记为可用空间,因此它们可以被稍后的INSERT或覆盖UPDATE。因此,旧版本的UPDATEd 行可能仍然存在,存在但无法访问。

此外,Pg 分两个阶段写入。第一个数据被写入预写日志 (WAL)。只有当它被写入 WAL 并命中磁盘后,它才会被复制到“堆”(主表),可能会覆盖那里的旧数据。WAL 内容bgwriter通过定期检查点复制到主堆。默认情况下,检查点每 5 分钟发生一次。如果您设法在检查点发生之前停止数据库,并通过硬杀死它、拔掉机器上的插头或使用模式来停止它pg_ctlimmediate您可能已经在检查点发生之前捕获了数据,所以您的旧数据是更有可能仍然在堆中。

现在您已经制作了数据目录的完整文件系统级副本,如果您确实需要,您可以启动数据库备份;数据仍然会消失,但你已经尽你所能给自己一些可能恢复它的希望。考虑到选择,为了安全起见,我可能会关闭数据库。

恢复

您现在可能需要聘请 PostgreSQL 内部专家来协助您进行数据恢复尝试。准备好为专业人士支付他们的时间,可能是相当多的时间。

我在 Pg 邮件列表上发布了有关此内容的信息,并将Виктор Егоров 链接到 depesz 在 pg_dirtyread 上的帖子,这看起来正是您想要的,尽管它不会恢复TOASTed 数据,因此它的实用性有限。试试看,如果你幸运的话,它可能会奏效。

请参阅:GitHub 上的 pg_dirtyread

我已经删除了我在本节中编写的内容,因为它已被该工具淘汰。

另请参阅PostgreSQL 行存储基础知识

预防

请参阅我的博客条目防止 PostgreSQL 数据库损坏


在一个半相关的旁注中,如果您使用两阶段提交,您可以ROLLBACK PREPARED为准备提交但未完全提交的事务。这大约是您最接近回滚已提交事务的时间,并且不适用于您的情况。

于 2012-09-18T07:50:01.493 回答