Whoami:5年+金融、政府、医疗领域工作经验的DBACertificate:PGCM、OCP、YCPSkill:Oracle、Mysql、PostgreSQL、国产数据库Platform:CSDN、墨天轮、公众号(呆呆的私房菜)
在数据库层面误操作导致的数据丢失,可能由DDL或DML操作引起的;那么,哪种场景的数据恢复的可能性更大呢?
DDL操作:在PostgreSQL数据库中,表通过oid命名规则,以文件的方式存放于$PGDATA/base/dbid/relfilenode中;如果执行drop操作的话,会将整个文件进行整体删除,此时操作系统上的文件已经不存在了,因此在数据库层面上很难恢复,只能通过恢复磁盘的方式去找回数据,但是这种方式找回数据的概率也很小!再一次敲响给我们敲响警钟:数据库一定一定一定要做好定期备份!!! DML操作:结合PostgreSQL的MVCC实现,数据库误操作update或delete,我们可以通过针对不同的场景,采用不同的方案来尝试数据恢复。
pg_resetwal 用于重置PostgreSQL数据库的wal日志和pg_control文件中的一些控制信息。既如此,那么我们也可以利用pg_resetwal把数据库回滚到一个一致的状态点。
1. 创建测试环境postgres=# CREATE TABLE test1 (id INT, name VARCHAR(10));CREATE TABLEpostgres=# INSERT INTO test1 VALUES (1, 'asd');INSERT 0 1postgres=# INSERT INTO test1 VALUES (2, 'qwe');INSERT 0 1postgres=# INSERT INTO test1 VALUES (3, 'zxc');INSERT 0 12. 模拟误删数据postgres=# DELETE FROM test1 WHERE id > 1;DELETE 23. 查看当前LSN及WAL文件postgres=# SELECT pg_current_wal_lsn(), pg_walfile_name(pg_current_wal_lsn()), pg_walfile_name_offset(pg_current_wal_lsn());pg_current_wal_lsn | pg_walfile_name | pg_walfile_name_offset--------------------+--------------------------+------------------------------------0/17377D8 | 000000010000000000000001 | (000000010000000000000001,7567320)(1 row)4. 查找误操作的事务号pg_waldump -b -p home/postgres/pg15/data/pg_wal 000000010000000000000001 > wal.log日志如下:rmgr: Heap len (rec/tot): 63/ 63, tx: 735, lsn: 0/01737608, prev 0/01737450, desc: INSERT+INIT off 1 flags 0x00blkref #0: rel 1663/5/24576 fork main blk 0rmgr: Transaction len (rec/tot): 34/ 34, tx: 735, lsn: 0/01737648, prev 0/01737608, desc: COMMIT 2024-12-20 11:52:10.475243 CSTrmgr: Heap len (rec/tot): 63/ 63, tx: 736, lsn: 0/01737670, prev 0/01737648, desc: INSERT off 2 flags 0x00blkref #0: rel 1663/5/24576 fork main blk 0rmgr: Transaction len (rec/tot): 34/ 34, tx: 736, lsn: 0/017376B0, prev 0/01737670, desc: COMMIT 2024-12-20 11:52:10.477603 CSTrmgr: Heap len (rec/tot): 63/ 63, tx: 737, lsn: 0/017376D8, prev 0/017376B0, desc: INSERT off 3 flags 0x00:2024-12-20 12:04:49.907 CST [1938] LOG: checkpoint starting: time2024-12-20 12:04:49.927 CST [1938] LOG: checkpoint complete: wrote 3 buffers (0.0%); 0 WAL file(s) added, 0 removed, 0 recycled; write=0.001 s, sync=0.004 s, total=0.021 s; sync files=2, longest=0.003 s, average=0.002 s; distance=0 kB, estimate=0 kBblkref #0: rel 1663/5/24576 fork main blk 0rmgr: Transaction len (rec/tot): 34/ 34, tx: 737, lsn: 0/01737718, prev 0/017376D8, desc: COMMIT 2024-12-20 11:52:10.749071 CSTrmgr: Heap len (rec/tot): 54/ 54, tx: 738, lsn: 0/01737740, prev 0/01737718, desc: DELETE off 2 flags 0x00 KEYS_UPDATEDblkref #0: rel 1663/5/24576 fork main blk 0rmgr: Heap len (rec/tot): 54/ 54, tx: 738, lsn: 0/01737778, prev 0/01737740, desc: DELETE off 3 flags 0x00 KEYS_UPDATEDblkref #0: rel 1663/5/24576 fork main blk 0rmgr: Transaction len (rec/tot): 34/ 34, tx: 738, lsn: 0/017377B0, prev 0/01737778, desc: COMMIT 2024-12-20 11:52:14.104171 CST5. 关闭数据库,根据wal日志回滚到目标事务IDpg_ctl stop -D $PGDATApg_resetwal -x 738 -D $PGDATA6. 启动数据库并查看数据pg_ctl start -D $PGDATApostgres=# select * from test1;id | name----+------1 | asd2 | qwe3 | zxc(3 rows)
pg_recovery是一款基于 PostgreSQL 的数据恢复工具,主要针对在执行了 update、delete、rollback、drop column 等操作后的数据恢复。
1. 创建测试环境postgres=# CREATE TABLE test2 (id INT, name VARCHAR(10));CREATE TABLEpostgres=# INSERT INTO test2 VALUES (1, 'asd');INSERT 0 1postgres=# INSERT INTO test2 VALUES (2, 'qwe');INSERT 0 1postgres=# INSERT INTO test2 VALUES (3, 'zxv');INSERT 0 1postgres=# DELETE FROM test2 WHERE id > 1;DELETE 22. 下载pg_recovery,上传安装包并解压,编译安装https://github.com/radondb/pg_recoveryunzip pg_recovery-master.zipcd /home/postgres/pg15/soft/contrib/pg_recovery-mastermake && make install3. 创建pg_recovery扩展postgres=# CREATE EXTENSION pg_recovery;CREATE EXTENSION4. 查看误删除数据postgres=# SELECT * FROM pg_recovery ('test2') AS (id int, name varchar(10));id | name----+------2 | qwe3 | zxv(2 rows)
pg_dirtyread是一个第三方PostgreSQL扩展,它允许用户读取数据库文件中的“脏”数据,即那些被标记为删除或不再可见的数据。这个扩展对于数据恢复和调试非常有用,尤其是在需要恢复被删除或更新前的数据时。
1. 创建测试环境postgres=# CREATE TABLE test3 (id INT, name VARCHAR(10));CREATE TABLEpostgres=# INSERT INTO test3 VALUES (1, 'asd');INSERT 0 1postgres=# INSERT INTO test3 VALUES (2, 'qwe');INSERT 0 1postgres=# INSERT INTO test3 VALUES (3, 'zxv');INSERT 0 1postgres=# DELETE FROM test3 WHERE id > 1;DELETE 22. 下载pg_recovery,上传安装包并解压,编译安装https://github.com/df7cb/pg_dirtyreadtar xzf pg_dirtyread-2.7.tar.gzcd /home/postgres/pg15/soft/contrib/pg_dirtyread-2.7make && make install3. 创建pg_recovery扩展postgres=# CREATE EXTENSION pg_dirtyread;CREATE EXTENSION4. 查看表中所有数据行,包括已经被标记为删除或不再可见的行postgres=# SELECT * FROM pg_dirtyread('test3') AS (id INT, name VARCHAR(10));id | name----+------1 | asd2 | qwe3 | zxv(3 rows)
pg_filedump是一个命令行工具,可以在服务端执行,不需要连接数据库。这个工具可以分析出数据文件中数据的详细数据,内容格式与pageinspect类似。它可以直接读取文件,适用于严重灾难的情况,但是需要知道具体的文件位置,适用性不强。 pg_filedump可以直接通过SQL将数据一键找回,需要编译找回数据方法。不过,它无法找回自定义数据类型的数据,并且由于只能在服务端执行,不适用于云数据库的数据找回。
1. 创建测试环境postgres=# CREATE TABLE test4 (id INT, name VARCHAR(10));CREATE TABLEpostgres=# INSERT INTO test4 VALUES (1, 'asd');INSERT 0 1postgres=# INSERT INTO test4 VALUES (2, 'qwe');INSERT 0 1postgres=# INSERT INTO test4 VALUES (3, 'zxv');INSERT 0 1postgres=# DELETE FROM test4 WHERE id > 1;DELETE 22. 下载pg_recovery,上传安装包并解压,编译安装https://github.com/df7cb/pg_filedumptar xzf pg_filedump-REL_17_1.tar.gzcd /home/postgres/pg15/soft/contrib/pg_filedump-REL_17_1make && make install3. 查看test4表文件存放路径postgres=# SELECT pg_relation_filepath('test4');pg_relation_filepath----------------------base/5/24635(1 row)4. 解析文件内容pg_filedump -D int,varchar home/postgres/pg15/data/base/5/24635 | grep COPYCOPY: 1 asdCOPY: 2 qweCOPY: 3 zxv
pageinspect是 PostgreSQL 自带的一个扩展,它提供了查看数据库页级别的信息的功能。虽然它不直接用于数据恢复,但可以辅助我们在数据恢复过程中查看和分析数据。
1. 创建测试环境postgres=# CREATE TABLE test3 (id INT, name VARCHAR(10));CREATE TABLEpostgres=# INSERT INTO test3 VALUES (1, 'asd');INSERT 0 1postgres=# INSERT INTO test3 VALUES (2, 'qwe');INSERT 0 1postgres=# INSERT INTO test3 VALUES (3, 'zxv');INSERT 0 1postgres=# DELETE FROM test3 WHERE id > 1;DELETE 23. 编译安装pageinspect插件cd /home/postgres/pg15/soft/contrib/pageinspectmake && make install4. 创建pageinspect扩展postgres=# create extension pageinspect;CREATE EXTENSION5. 识别被删除的数据postgres=# SELECT * FROM heap_page_items(get_raw_page('test3', 0))postgres-# WHERE t_xmax <> 0;lp | lp_off | lp_flags | lp_len | t_xmin | t_xmax | t_field3 | t_ctid | t_infomask2 | t_infomask | t_hoff | t_bits | t_oid | t_data----+--------+----------+--------+--------+--------+----------+--------+-------------+------------+--------+--------+-------+--------------------2 | 8128 | 1 | 32 | 747 | 749 | 0 | (0,2) | 8194 | 1282 | 24 | | | \x02000000097177653 | 8096 | 1 | 32 | 748 | 749 | 0 | (0,3) | 8194 | 1282 | 24 | | | \x03000000097a7876(2 rows)6. 提取出字段数据postgres=# SELECT tuple_data_split((SELECT oid FROM pg_class WHERE relname = 'test3')::oid, t_data, t_infomask, t_infomask2, t_bits)postgres-# FROM heap_page_items(get_raw_page('test3', 0))postgres-# WHERE t_xmax <> 0;tuple_data_split-------------------------------{"\\x02000000","\\x09717765"}{"\\x03000000","\\x097a7876"}(2 rows)7. 转换成可视数据......
本文内容就到这啦,阅读完本篇,相信你已经掌握误删数据时PostgreSQL恢复数据的方法了吧!我们下篇再见!

文章转载自呆呆的私房菜,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。




