我提交了一个不正确的UPDATE
声明并丢失了一些数据。
在我已经提交之后,现在可以回滚吗?
任何帮助?
ROLLBACK
说NOTICE: there is no transaction in progress
。
答案 0 :(得分:86)
不,您无法撤消,回滚或撤消提交。
(注意:如果您从文件系统中删除了数据目录,请不要停止数据库。以下建议适用于DELETE
或类似的意外提交,而不是rm -rf /data/directory
方案。
如果此数据很重要,现在停止您的数据库并且不要重新启动它。使用pg_ctl stop -m immediate
以便在关闭时不运行检查点。
提交后,您无法回滚事务。您需要从备份中恢复数据,或使用point-in-time recovery,必须在事故发生前设置。
如果您没有设置任何PITR / WAL归档并且没有备份,那么您将遇到麻烦。
数据库停止后,您应该创建整个数据目录的文件系统级别 - 包含base
,pg_clog
等的文件夹。复制所有数据到一个新的位置。不要对新位置的副本执行任何操作,如果您没有备份,则唯一希望恢复数据。如果可以,请在某些可移动存储上制作另一个副本,然后从计算机上拔下该存储。请记住,您需要绝对数据目录的每个部分,包括pg_xlog
等。没有任何部分是不重要的。
究竟如何制作副本取决于您正在运行的操作系统。数据目录取决于您正在运行的操作系统以及如何安装PostgreSQL。
如果你足够快地停止你的数据库,你可能希望从表中恢复一些数据。那是因为PostgreSQL使用multi-version concurrency control (MVCC)来管理对其存储的并发访问。有时,它会将您更新的行的INSERT
或UPDATE
覆盖这些行。因此,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数据所以它有限效用。尝试一下,如果你很幸运,它可能会起作用。
我已删除了我在本节中所写的内容,因为该工具已将其废弃。
另见PostgreSQL row storage fundamentals
请参阅我的博客文章Preventing PostgreSQL database corruption。
在半相关的旁注上,如果你使用two phase commit,你可以ROLLBACK PREPARED
进行为提交准备但未完全提交的转换。这是你回滚已经提交的交易的最接近的,并不适用于你的情况。