ud_dirtyread
简介
ud_dirtyread 是脏读插件,用于读取那些已经删除但未被清理的数据。当误操作delete数据时,可以使用它从脏数据中恢复出来。 不支持 DDL 操作和 truncate 操作的恢复。
前提要求
未手动或自动执行 vacuum 清理操作
查询上一次 vacuum 执行时间,如已经执行了清理,则数据无法恢复。
select relname,last_vacuum, last_autovacuum, last_analyze, vacuum_count, autovacuum_count, last_autoanalyze from pg_stat_user_tables;
注意事项
不建议在生产环境直接执行本节的所有操作。
建议将当前所有文件复制到一个独立的机器进行恢复操作,避免对当前环境造成更大的数据损坏。
在将结果恢复到生产环境时,建议先备份生产环境当前的所有数据。
安装
udb-tx-v22.4.22及以后的版本,已启用 ud_dirtyread, 直接使用即可。 udb-tx-v22.4.22及以前的版本,按以下步骤安装启用。
【附件】ud_dirtyread.zip 如下载失败请联系技术支持获取。
启用
ud_dirtyread.so 放到安装目录的lib/ 下
ud_dirtyread.control 和 ud_dirtyread–*.sql 放到安装目录的share/extension/ 下
chown -R udb.udb 安装目录/lib/ud_dirtyread.so
chown -R udb.udb 安装目录/share/extension/ud_dirtyread*
验证安装
waltest=# CREATE EXTENSION ud_dirtyread;
CREATE EXTENSION
使用示例
创建测试数据
waltest=# select * from tb1;
id | name
----+------
1 | a
2 | b
(2 rows)
waltest=# \dt tb1;
List of relations
Schema | Name | Type | Owner
--------+------+-------+-------
public | tb1 | table | unvdb
(1 row)
waltest=# \d tb1;
Table "public.tb1"
Column | Type | Collation | Nullable | Default
--------+------------------------+-----------+----------+---------
id | integer | | not null |
name | character varying(255) | | |
Indexes:
"tb1_pkey" PRIMARY KEY, btree (id)
查看当前数据元组信息
waltest=# select xmin,xmax,ctid,* from tb1;
xmin | xmax | ctid | id | name
------+------+-------+----+------
1650 | 0 | (0,1) | 1 | a
1651 | 0 | (0,2) | 2 | b
(2 rows)
查看是否为脏数据,dead列为f,表示非死数据
waltest=# select * from ud_dirtyread('tb1') as foo(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean,id int,name varchar(255));
tableoid | ctid | xmin | xmax | cmin | cmax | dead | id | name
----------+-------+------+------+------+------+------+----+------
66027 | (0,1) | 1650 | 0 | 0 | 0 | f | 1 | a
66027 | (0,2) | 1651 | 0 | 0 | 0 | f | 2 | b
(2 rows)
删除数据
waltest=# delete from tb1 where id=1;
DELETE 1
waltest=# select * from tb1;
id | name
----+------
2 | b
(1 row)
修改数据
waltest=# update tb1 set name='bb' where id=2;
UPDATE 1
查看已删除未清理的脏数据
waltest=# select * from ud_dirtyread('tb1') as foo(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean,id int,name varchar(255));
tableoid | ctid | xmin | xmax | cmin | cmax | dead | id | name
----------+-------+------+------+------+------+------+----+------
66027 | (0,1) | 1650 | 1652 | 0 | 0 | t | 1 | a
66027 | (0,2) | 1651 | 1653 | 0 | 0 | t | 2 | b
66027 | (0,3) | 1653 | 0 | 0 | 0 | f | 2 | bb
(3 rows)
会发现id=1的那条数据状态 dead=t 更新的id=2那条数据的事务已经由1651变为1653,原来的状态变为了删除,值已经变更为bb
删除列
waltest=# alter table tb1 drop column name;
ALTER TABLE
waltest=# select * from tb1;
id
----
2
(1 row)
查看已删除列的脏数据,此时要用 dropped_n 来代替
waltest=# select * from ud_dirtyread('tb1') as foo(tableoid oid, ctid tid, xmin xid, xmax xid, cmin cid, cmax cid, dead boolean,id int,dropped_2 varchar(255));
tableoid | ctid | xmin | xmax | cmin | cmax | dead | id | dropped_2
----------+-------+------+------+------+------+------+----+-----------
66027 | (0,1) | 1650 | 1652 | 0 | 0 | t | 1 | a
66027 | (0,2) | 1651 | 1653 | 0 | 0 | t | 2 | b
66027 | (0,3) | 1653 | 0 | 0 | 0 | f | 2 | bb
(3 rows)