PostgreSQL中删除的数据能否恢复

问题的提出

  • 有人问PostgreSQL数据库中刚刚删除的数据能否被恢复?
  • 或更进一步,如果如要在一个事务中做了一系列的更新、删除、插入的操作后,把这个事务提交之后又后悔了,能否恢复到之前的状态?

当然如果数据库有备份,可以直接从备份的数据中恢复,本文讨论的是没有备份的情况下能否恢复。

理论分析

从PostgreSQL多版本实现的原理上,这是有可能的。因为PostgreSQL的多版本原理是旧数据并不删除:

  • 对于删除数据的操作,只是把行上的xmax改成当前的事务id
  • 对于更新操作,只是把原先行上xmax改成当前的事务id,并插入一个新行,而新行上的xmin置为当前的事务id
  • 事务的状态是记录在commit log中的,如果事务提交,只是把commit log中相应的事务状态改成“已提交状态(TRANSACTION_STATUS_COMMITTED )”,如果事务回滚,则把commit log中的事务状态改成“事务回滚(TRANSACTION_STATUS_ABORTED )”

所以从理论上说,只要把在commit log中刚提交事务状态从“TRANSACTION_STATUS_COMMITTED”改成“TRANSACTION_STATUS_ABORTED”,原先的事务就会做废,就能回到事务之前的状态。 但这个恢复有一个前提就是旧版本的数据没有被vacuum垃圾回收进程清理掉,如果旧版本的数据已被vacuum垃圾回收进程给清理掉了,就不能恢复了。所以如果作了删除数据的操作后,马上把数据库停下来,这时autovacuum进程还没有把旧版本的数据给清理掉时,数据是可以恢复的。 但仅仅是把commit log中的事务状态改一下,就能恢复数据吗?答案也是否定的,事情没有这么简单,原因是多版本的可见性判断不仅仅是由commit log中的事务状态的决定的,行上还有t_infomask状态位中的hint信息来决定。如果hint已表示该行上的事务已被提交,则不需要再到commit log中来查看事务的状态了。这个功能主要是为了提高性能,因为到clog中判断行的可见性,而clog中只有8个块是缓存在共享内存中的,如果判断每个行都去查找clog,效率太低了。具体这一部分的内容可以见我的另一篇blog: PostgreSQL中行的可见性判断中t_infomask字段的作用 所以要想恢复数据,还需要把相应表文件中各行上的t_infomask状态中的hint标志位给清除掉之后,数据才能恢复回来。

恢复的工具

因为整个恢复的过程比较复杂,为此我写了一个工具叫pg_fix,放在github上:https://github.com/osdba/pg_fix,供大家研究使用。 首先使用这个工具可以查询某一个表的数据文件中各行的状态:

使用这个工具可以清理表的数据文件中的t_infomask中的hint信息,在清理hint状态之前,先查看行上的t_maskinfo状态:

然后执行下面命令清除行上的hint状态:

清除完后,我们再看行上的t_infomask状态:

查询和改变事务的状态的方法如下: 查询事务xid=11的状态的命令如下:

修改事务xid=11的状态的命令如下:

其中-s后的值表示要把事务改成什么状态,事务的状态值有四种,为0~3,意思如下:

  • #define TRANSACTION_STATUS_IN_PROGRESS 0x00
  • #define TRANSACTION_STATUS_COMMITTED 0x01
  • #define TRANSACTION_STATUS_ABORTED 0x02
  • #define TRANSACTION_STATUS_SUB_COMMITTED 0x03

当然上面使用pg_fix工具直接修改表中数据和commit log中事务的状态都必须是数据库停下来的情况。 另本文的目的主要是为了研究PostgreSQL的一些原理,所以以上这些操作通常不要拿到生产数据库上去试!!!

作者:唐成

沃趣科技首席数据库架构师

原文发布于微信公众号 - 沃趣科技(woqutech)

原文发表时间:2015-12-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏点滴积累

OpenStack(企业私有云)万里长征第六步——OpenStack网络及虚拟机存储位置

一、前言 昨天又装了一遍OpenStack。码农这项工作就如同人生,永远有你想不到的意外在等着你,时而是惊喜时而是悲伤。在装的过程中倒是很顺利,只是在安装完成之...

42210
来自专栏杨建荣的学习笔记

从零开始搭建Nginx和Tomcat的web集群环境

一直以来对于web服务器对tomcat还是很熟悉了,但是很对于nginx还是有些陌生,一看到nginx的配置就让人有一种莫名的排斥,这就是对于陌生的恐惧,我们今...

3875
来自专栏FreeBuf

打狗棒法之:Cknife(C刀)自定义模式秒过安全狗

免责声明:本站提供安全工具、程序(方法)可能带有攻击性,仅供安全研究与教学之用,风险自负! 0x00 前言 很多朋友在使用Cknife时都误以为她只是菜刀的跨平...

3188
来自专栏北京马哥教育

手把手教你用永恒之蓝(Eternalblue)勒索病毒漏洞的高阶用法

? 作者:7sDream 来源: https://www.zybuluo.com/7sDream/note/729295 安装 MSF Linux & Ma...

4798
来自专栏FreeBuf

如何检测并移除WMI持久化后门?

Windows Management Instrumentation(WMI)事件订阅,是一种常被攻击者利用来在端点上建立持久性的技术。因此,我决定花一些时间研...

1323
来自专栏Albert陈凯

2018-10-09 lombok 生产环境报错SEVERE: Unable to process Jar entry [module-info.class] from Jar [jar:fil...

老师您好,课程里面用的lombok,感觉很方便,我就在我写的一个测试项目里面也用的这个。在idea里面用tomcat是可以正常运行的。但是打好包以后,放到服务器...

3.7K2
来自专栏北京马哥教育

LINUX上MYSQL优化三板斧

云豆贴心提醒,本文阅读时间7分钟 现在MySQL运行的大部分环境都是在Linux上的,如何在Linux操作系统上根据MySQL进行优化,我们这里给出一些通用简...

3027
来自专栏杨建荣的学习笔记

MySQL审计插件使用和对比

数据库审计是数据库安全中很重要的一个环节,说到审计,有些上市公司内部还会根据塞班斯法案,进行404审计等等。 而最基本的审计还是需要的,有些同学可能...

7109
来自专栏菩提树下的杨过

Asp.Net4.0/VS2010新变化(1):web.config与publish

Vs2010正式版据说4月12号就要发行,是时候摆弄一下它了  新建web application后,最直观的一个变化就在于web.config变干净了: ? ...

2108
来自专栏gaoqin31

PHP使用守护进程处理队列

  项目是棋牌,web架构是典型的lnmp,server产生的牌局通过http协议请求webserver,由php分析并持久化到mysql,中间参杂了很多业务逻...

1867

扫码关注云+社区

领取腾讯云代金券