PostgreSQL中删除的数据能否恢复
来源:互联网 发布:linux get文件命令 编辑:程序博客网 时间:2024/06/07 03:06
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,供大家研究使用。
首先使用这个工具可以查询某一个表的数据文件中各行的状态:
osdba-mac:pg_fix osdba$ ./pg_fix show_tuple -f 16384
lp off flags lp_len xmin xmax field3 blkid posid infomask infomask2 hoff oid
---- ----- ----- ------ ---------- ---------- ---------- ----- ------------- --------- ---- ----------
1 8152 1 33 1001 1002 0 0 3 2 4002 24 0
2 8112 1 33 1001 1002 0 0 4 2 4002 24 0
3 8072 1 33 1002 0 0 0 3 2002 8002 24 0
4 8032 1 33 1002 0 0 0 4 2002 8002 24 0
使用这个工具可以清理表的数据文件中的t_infomask中的hint信息,在清理hint状态之前,先查看行上的t_maskinfo状态:
osdba-mac:pg_fix osdba$ ./pg_fix show_tuple -f 16384
lp off flags lp_len xmin xmax field3 blkid posid infomask infomask2 hoff oid
---- ----- ----- ------ ---------- ---------- ---------- ----- ------------- --------- ---- ----------
1 8152 1 33 1001 1002 0 0 3 502 4002 24 0
2 8112 1 33 1001 1002 0 0 4 502 4002 24 0
3 8072 1 33 1002 0 0 0 3 2902 8002 24 0
4 8032 1 33 1002 0 0 0 4 2902 8002 24 0
然后执行下面命令清除行上的hint状态:
osdba-mac:pg_fix osdba$ ./pg_fix clean_tuple_hint -f 16384
清除完后,我们再看行上的t_infomask状态:
osdba-mac:pg_fix osdba$ ./pg_fix show_tuple -f 16384
lp off flags lp_len xmin xmax field3 blkid posid infomask infomask2 hoff oid
---- ----- ----- ------ ---------- ---------- ---------- ----- ------------- --------- ---- ----------
1 8152 1 33 1001 1002 0 0 3 2 4002 24 0
2 8112 1 33 1001 1002 0 0 4 2 4002 24 0
3 8072 1 33 1002 0 0 0 3 2002 8002 24 0
4 8032 1 33 1002 0 0 0 4 2002 8002 24 0
查询和改变事务的状态的方法如下:
查询事务xid=11的状态的命令如下:
osdba-mac:pg_fix osdba$ ./pg_fix get_xid_status -f 0000.bkk -x 11
xid(11) status is 1(COMMITTED)
修改事务xid=11的状态的命令如下:
osdba-mac:pg_fix osdba$ ./pg_fix set_xid_status -f 0000.bkk -x 11 -s 0
xid(11) status from 1(COMMITTED) change to 0(IN_PROGRESS)
其中-s后的值表示要把事务改成什么状态,事务的状态值有四种,为0~3,意思如下:
§ #define TRANSACTION_STATUS_IN_PROGRESS0x00
§ #define TRANSACTION_STATUS_COMMITTED0x01
§ #define TRANSACTION_STATUS_ABORTED 0x02
§ #define TRANSACTION_STATUS_SUB_COMMITTED0x03
当然上面使用pg_fix工具直接修改表中数据和commit log中事务的状态都必须是数据库停下来的情况。
另本文的目的主要是为了研究PostgreSQL的一些原理,所以以上这些操作通常不要拿到生产数据库上去试!!!
- PostgreSQL中删除的数据能否恢复
- PostgreSQL中删除的数据能否恢复
- 恢复sqlserver中被删除的数据
- PostgreSQL 恢复数据库数据
- postgresql数据备份恢复
- 恢复oracle中被删除的表的数据
- 如何恢复DB2中误删除表的数据
- Oracle数据库中误删除数据后恢复的方法
- oracle数据库表中数据删除的恢复方法
- 在oracle中,如何恢复不小心删除的数据?
- 恢复delete删除的数据
- oracle恢复删除的数据
- oracle恢复删除的数据
- 恢复Oracle删除的数据
- oracle恢复删除的数据
- 恢复误删除的数据
- oracle恢复删除的数据
- oracle恢复删除的数据
- genbindings_wawagame.py
- 《SQL必知必会》-- 笔记(1-5)
- VA Snippet Editor 自动生成注释 自用宏
- Java 的数值是怎么存储的
- node-webkit:开发桌面+WEB混合型应用的神器
- PostgreSQL中删除的数据能否恢复
- ww_gui.ini
- 机器学习算法一览,应用建议与解决思路
- Android 2016最热网络请求开发框架之Okhttp ,facebook强烈推荐必备开发
- 用node-webkit把web应用打包成桌面应用
- java中“==”、equals和hashCode的区别
- php 利用curl get post数据
- Mac下Android Studio 使用git版本控制个人心得
- css 常用总结