标签云
asm恢复 bbed bootstrap$ dul kcbzib_kcrsds_1 kccpb_sanity_check_2 kcratr_nab_less_than_odr MySQL恢复 obet ORA-00312 ORA-00704 ORA-00742 ORA-01110 ORA-01200 ORA-01555 ORA-01578 ORA-01595 ORA-600 2662 ORA-600 2663 ORA-600 3020 ORA-600 4000 ORA-600 4137 ORA-600 4193 ORA-600 4194 ORA-600 16703 ORA-600 kcbzib_kcrsds_1 ORA-600 KCLCHKBLK_4 ORA-600 kcratr_nab_less_than_odr ORA-15042 ORA-15196 ORACLE 12C oracle dul ORACLE PATCH Oracle Recovery Tools oracle加密恢复 oracle勒索 oracle勒索恢复 oracle异常恢复 ORACLE恢复 Oracle 恢复 ORACLE数据库恢复 oracle碎片 OSD-04016 YOUR FILES ARE ENCRYPTED 比特币加密文章分类
- MongoDB (1)
- MongoDB恢复 (1)
- Others (2)
- 中间件 (2)
- WebLogic (2)
- 操作系统 (112)
- 数据库 (1,878)
- DB2 (22)
- MySQL (82)
- Oracle (1,704)
- Data Guard (53)
- EXADATA (8)
- GoldenGate (24)
- ORA-xxxxx (168)
- ORACLE 12C (72)
- ORACLE 18C (6)
- ORACLE 19C (15)
- ORACLE 21C (3)
- Oracle 23ai (8)
- Oracle ASM (72)
- Oracle Bug (8)
- Oracle RAC (56)
- Oracle 安全 (6)
- Oracle 开发 (28)
- Oracle 监听 (29)
- Oracle备份恢复 (659)
- Oracle安装升级 (107)
- Oracle性能优化 (62)
- 专题索引 (5)
- 勒索恢复 (91)
- PostgreSQL (37)
- pdu工具 (7)
- PostgreSQL恢复 (13)
- SQL Server (34)
- SQL Server恢复 (14)
- TimesTen (7)
- 达梦数据库 (5)
- 达梦恢复 (3)
- 生活娱乐 (2)
- 至理名言 (11)
- 虚拟化 (2)
- VMware (2)
- 软件开发 (51)
- Asp.Net (9)
- JavaScript (12)
- PHP (2)
- 小工具 (34)
- MongoDB (1)
-
最近发表
- 由于con$.con#值达到极限,触发数据库增加约束报ORA-600 12807错误
- MongoDB 离线提取工具—mongoext
- .bres勒索病毒加密数据库dmp文件可恢复
- ORA-600 krsm_mrp_rebuild_lf_list.lno_mismatch
- 记录一次0丢失的ORA-00354: 损坏重做日志块标头故障恢复
- 不当数据库恢复操作导致一个月数据丢失
- obet快速修复oracle 位图损坏块
- 不太常见的10.2.0.1的oracle redo损坏恢复
- obet forcecopy功能抢救硬件故障中的数据文件
- kcratr_nab_less_than_odr和system坏块故障处理
- 通过obet 恢复system坏块,打开数据库
- obet dbv功能完整说明
- 分享一例运行在aix上的sap系统数据库恢复过程
- OBET-Oracle Block Editor Tool使用说明
- 几乎动用了所有手段的Oracle故障恢复
- Oracle Block Edit Tool (obet) 功能增强–2026.07
- Oracle 19c 202607补丁(RUs+OJVM)-19.32
- Patch_SCN快速修复ORA-01555数据库open故障
- 快速处理 ORA-01210: data file header is media corrupt 故障
- ORA-00314: log 3 of thread 1, expected sequence# N doesn’t match 0
分类目录归档:PostgreSQL恢复
pg误删除数据恢复(PostgreSQL delete数据恢复)
应用维护人员通过应用程序误删除了一些数据,希望对其进行恢复.通过咨询确认是PostgreSQL数据,wal和arch文件都在,取客户删除数据时间点相关wal文件

然后让客户提供具体涉及误删除的相关的库和表信息

通过工具解析wal日志,比较顺利的获取到了undo sql语句
Switch wal to 0000000300000525000000B0 on time 2025-03-05 22:23:14.263661+08 Switch wal to 0000000300000525000000B1 on time 2025-03-05 22:23:14.423082+08 Switch wal to 0000000300000525000000B2 on time 2025-03-05 22:23:15.983833+08 Switch wal to 0000000300000525000000B3 on time 2025-03-05 22:23:17.802107+08 Switch wal to 0000000300000525000000B4 on time 2025-03-05 22:23:18.942125+08 Switch wal to 0000000300000525000000B5 on time 2025-03-05 22:23:20.293585+08 Switch wal to 0000000300000525000000B6 on time 2025-03-05 22:23:21.531484+08 Switch wal to 0000000300000525000000B7 on time 2025-03-05 22:23:24.217501+08 Switch wal to 0000000300000525000000B8 on time 2025-03-05 22:23:27.504164+08 Switch wal to 0000000300000525000000B9 on time 2025-03-05 22:23:29.260754+08 Switch wal to 0000000300000525000000BA on time 2025-03-05 22:23:33.544486+08 Switch wal to 0000000300000525000000BB on time 2025-03-05 22:23:35.568116+08 Switch wal to 0000000300000525000000BC on time 2025-03-05 22:23:37.329659+08 Switch wal to 0000000300000525000000BD on time 2025-03-05 22:23:38.971834+08 Switch wal to 0000000300000525000000BE on time 2025-03-05 22:23:39.922353+08 Switch wal to 0000000300000525000000BF on time 2025-03-05 22:23:40.897294+08

然后把这些sql语句反向插入到生产库,完成这些误操作数据的恢复

如果此类的数据库(oracle,mysql,sql server,PostgreSQL)等恢复请求,需要专业恢复技术支持,请联系我们:
电话/微信:17813235971 Q Q:107644445
E-Mail:dba@xifenfei.com
发表在 PostgreSQL恢复
评论关闭
PostgreSQL解析wal日志之—walminer
在oracle数据库中可以通过logminer实现对归档日志的解析,从而分析执行sql语句和undo sql,可以实现某些情况下数据库一些操作的定位(比如日志突然增加,数据突然丢失)以及一些故障的恢复(比如需要把update/delete执行的数据找回)等。在PostgreSQL数据库中walminer可以实现该需求,对pg的预写式日志(wal)的解析,具体见官网:https://gitee.com/movead/XLogMiner/
walminer安装
[postgres@localhost tmp]$ ls -l walminer_x86_64_centos_v4.6.0.tar.gz
-rw-r--r--. 1 root root 3866437 Apr 18 10:08 walminer_x86_64_centos_v4.6.0.tar.gz
[postgres@localhost tmp]$ tar xzvf walminer_x86_64_centos_v4.6.0.tar.gz
walminer_x86_64_centos_v4.6.0/
walminer_x86_64_centos_v4.6.0/bin/
walminer_x86_64_centos_v4.6.0/bin/walminer
walminer_x86_64_centos_v4.6.0/lib/
walminer_x86_64_centos_v4.6.0/lib/libpq.so.5.15
walminer_x86_64_centos_v4.6.0/lib/libpq.so.5
walminer_x86_64_centos_v4.6.0/lib/libpq.so
walminer_x86_64_centos_v4.6.0/share/
…………
[root@localhost ~]# mkdir -p /usr/local/walminer/
[root@localhost ~]# chown postgres:postgres /usr/local/walminer/
[root@localhost ~]# cp /tmp/walminer/walminer.license /usr/local/walminer/
[postgres@localhost bin]$ cd /tmp/walminer
[postgres@localhost walminer]$ cp -rp * /usr/local/walminer/
[postgres@localhost bin]$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/walminer/
[postgres@localhost bin]$ cd /usr/local/walminer/bin
[postgres@localhost bin]$ ./walminer help
walminer [command] [options]
COMMANDS
---------
#wal2sql
options
-D dic file for miner
-a out detail info for catalog change
-w wal file path to miner
-t dest of miner result(1 stdout, 2 file, 3 db)(stdout default)
-k boundary kind(1 all, 2 lsn, 3 time, 4 xid)(all default)
-m miner mode(0 nomal miner, 1 accurate miner)(nomal default) if k=2
-r the relname for single table miner
-s start location if k=2 or k=3, or xid if k = 4
if k=2 default the min lsn of input wals
if k=3 or k=4 you need input this
-e end wal location if k=2 or k=3
if k=2 default the max lsn of input wals
if k=3 you need input this
-f file to store miner result if t = 2
-d target database name if t=3(default postgres)
-h target database host if t=3(default localhost)
-p target database port if t=3(default 5432)
-u target database user if t=3(default postgres)
-W target user password if t=3
---------
#builtdic
options
-d target database name for connect(default postgres)
-h target database host(default localhost)
-p target database port(default 5432)
-u target database user(default postgres)
-W target user password
-D dic produce path
-f rewrite walminer dic if exists
-s only database pointed by -d
---------
#showdic
options
-D dic file to show
---------
#avatardic
options
-r avatar rel that new created
-n avatared relfilenode
-D avatared walminer dic path
-b target database name which contain rel pointed by -r
---------
#regress(not support for user)
options
-w test database wal path(default postgres)
-d test database name(default postgres)
-h test database host(default localhost)
-p test database port(default 5432)
-u test database user(default postgres)
-P apply database port
-W test user password
---------
#fosync
options
-D dic file for miner
-w wal file path to miner
-t dest of miner result(1 stdout, 2 file, 3 db, 4 apply)(stdout default)
-f file to store miner result if t = 2
-l lsn it start fync
-d target database name if t=3 or 4(default postgres)
-h target database host if t=3 or 4(default localhost)
-p target database port if t=3 or 4(default 5432)
-u target database user if t=3 or 4(default postgres)
-W target user password if t=3 or 4
---------
#pgto
options
-c configure path
-i to init a CDC configure
-r to run a CDC configure
Below is needed when -i
-d source database name(default postgres)
-h source database host(default localhost)
-p source database port(default 5432)
-u source database user(default postgres)
-w source user password
-D target database name
-H target database host
-P target database port
-U target database user
-W target user password
-K target database type(1 postgres) (support postgres only currently)
-s slot name need for CDC
---------
#waldump
options
-D dic file for miner
-w wal file path to dump
-t dest of miner result(1 stdout, 2 file)(stdout default)
-s start lsn to dump
-e end lsn to dump
-f file to store miner result if t = 2
-v verbose
---------
#################################################
[postgres@localhost bin]$
postgresql创建测试表和插入数据
[postgres@localhost ~]$ psql
psql (16.2)
Type "help" for help.
postgres=# select now();
now
-------------------------------
2024-04-25 10:48:00.602067-04
(1 row)
postgres=#
postgres=# create table t_walminer(id int,name varchar(100));
CREATE TABLE
postgres=# insert into t_walminer values(1,'www.xifenfei.com');
INSERT 0 1
postgres=# insert into t_walminer values(2,'www.orasos.com');
INSERT 0 1
postgres=# insert into t_walminer values(3,'xifenfei');
INSERT 0 1
postgres=# select * from t_walminer;
id | name
----+------------------
1 | www.xifenfei.com
2 | www.orasos.com
3 | xifenfei
(3 rows)
postgres=# select now();
now
-------------------------------
2024-04-25 10:49:47.036881-04
(1 row)
postgres=# select pg_switch_wal();
pg_switch_wal
---------------
0/D5023E8
(1 row)
walminer 生成字典
[postgres@localhost bin]$ ./walminer builtdic -D /usr/local/walminer/xifenfei.dic ################################################# Walminer for PostgreSQL wal Contact Author by mail 'lchch1990@sina.cn' Persional License for posgress ################################################# DIC INFO# sysid:7357852038421105818 timeline:1 dbversion:160002 walminer:4.6
walminer解析这个时间段wal操作
[postgres@localhost bin]$ ./walminer wal2sql -D /usr/local/walminer/xifenfei.dic -w /pg/database/data/pg_arch \ -k 3 -s 2024-04-24 -e 2024-04-26 ################################################# Walminer for PostgreSQL wal Contact Author by mail 'lchch1990@sina.cn' Persional License for posgress ################################################# Switch wal to /pg/database/data/pg_arch/000000010000000000000001 on time 2024-04-25 23:27:07.42721+08 Switch wal to /pg/database/data/pg_arch/000000010000000000000002 on time 2024-04-25 23:27:07.45369+08 Switch wal to /pg/database/data/pg_arch/000000010000000000000003 on time 2024-04-25 23:27:07.453891+08 Switch wal to /pg/database/data/pg_arch/000000010000000000000004 on time 2024-04-25 23:27:07.486403+08 Switch wal to /pg/database/data/pg_arch/000000010000000000000005 on time 2024-04-25 23:27:07.513144+08 Switch wal to /pg/database/data/pg_arch/000000010000000000000006 on time 2024-04-25 23:27:07.538212+08 Switch wal to /pg/database/data/pg_arch/000000010000000000000007 on time 2024-04-25 23:27:07.561455+08 Switch wal to /pg/database/data/pg_arch/000000010000000000000008 on time 2024-04-25 23:27:07.584488+08 Switch wal to /pg/database/data/pg_arch/000000010000000000000009 on time 2024-04-25 23:27:07.606598+08 Switch wal to /pg/database/data/pg_arch/00000001000000000000000A on time 2024-04-25 23:27:07.609195+08 Switch wal to /pg/database/data/pg_arch/00000001000000000000000B on time 2024-04-25 23:27:07.609344+08 Switch wal to /pg/database/data/pg_arch/00000001000000000000000C on time 2024-04-25 23:27:07.609364+08 Switch wal to /pg/database/data/pg_arch/00000001000000000000000D on time 2024-04-25 23:27:07.66233+08 Switch wal to /pg/database/data/pg_arch/00000001000000000000000E on time 2024-04-25 23:27:07.684666+08 Switch wal to /pg/database/data/pg_arch/00000001000000000000000F on time 2024-04-25 23:27:07.684877+08 Switch wal to /pg/database/data/pg_arch/000000010000000000000001 on time 2024-04-25 23:27:07.684899+08 Get start lsn 0/d4eb380 for time range Switch wal to /pg/database/data/pg_arch/00000001000000000000000D on time 2024-04-25 23:27:07.694947+08 [XID]=425507, [TOPXID]=0 [SQLNO]=1 [SQL]=INSERT INTO public.t_walminer(id ,name) VALUES(1 ,'www.xifenfei.com') [UNDO]=DELETE FROM public.t_walminer WHERE id=1 AND name='www.xifenfei.com' [database]=postgres [COMPLETE]=true [LSN]=0/d5021c8 [COMMITLSN]=0/d502218 [COMMITTIME]=2024-04-25 22:48:55.775279+08 ------------------------------------------------------ [XID]=425508, [TOPXID]=0 [SQLNO]=1 [SQL]=INSERT INTO public.t_walminer(id ,name) VALUES(2 ,'www.orasos.com') [UNDO]=DELETE FROM public.t_walminer WHERE id=2 AND name='www.orasos.com' [database]=postgres [COMPLETE]=true [LSN]=0/d502278 [COMMITLSN]=0/d5022c8 [COMMITTIME]=2024-04-25 22:49:10.769752+08 ------------------------------------------------------ [XID]=425509, [TOPXID]=0 [SQLNO]=1 [SQL]=INSERT INTO public.t_walminer(id ,name) VALUES(3 ,'xifenfei') [UNDO]=DELETE FROM public.t_walminer WHERE id=3 AND name='xifenfei' [database]=postgres [COMPLETE]=true [LSN]=0/d502328 [COMMITLSN]=0/d502370 [COMMITTIME]=2024-04-25 22:49:23.382642+08 ------------------------------------------------------ Switch wal to /pg/database/data/pg_arch/00000001000000000000000E on time 2024-04-25 23:27:07.696041+08 Switch wal to /pg/database/data/pg_arch/00000001000000000000000F on time 2024-04-25 23:27:07.696062+08 [postgres@localhost bin]$
通过上述测试证明walminer可以非常好的解析pg的wal日志
PostgreSQL恢复系列:pg_filedump批量处理
pg_filedump工具使用起来比较麻烦,主要存在问题:
1. 需要人工一个个枚举各个列类型无法实现批量恢复,参考以前写的PostgreSQL恢复系列:pg_filedump基本使用
2. 特别是在pg库无法正常运行的情况下,如果没有业务提供表创建语句,恢复基本上无法正常进行.
基于这两个问题,在以前的文章中写过PostgreSQL恢复系列:pg_filedump恢复字典构造,为了解决上述的两个,弄了一个pg_filedump_batch脚本实现批量恢复需求
在测试的pg库中创建了一些测试表,并查看部分表数据,便于对比后续恢复效果
postgres=# \d
List of relations
Schema | Name | Type | Owner
--------+----------------+-------+----------
public | t_tbs | table | postgres
public | t_xff | table | postgres
public | t_xff2 | table | postgres
public | t_xff3 | table | postgres
public | t_xff4 | table | postgres
public | t_xifenfei | table | postgres
public | tab_attribute | table | postgres
public | tab_class | table | postgres
public | tab_database | table | postgres
public | tab_namespace | table | postgres
public | tab_tablespace | table | postgres
public | tab_type | table | postgres
(12 rows)
postgres=# select * from tab_database;
oid | datname | datdba | encoding | datcollate | datctype | datistemplate | datallowconn | datconnlimit | datlastsysoi
d | datfrozenxid | datminmxid | dattablespace
-------+-------------+--------+----------+-------------+-------------+---------------+--------------+--------------+-------------
--+--------------+------------+---------------
14187 | postgres | 10 | 6 | en_US.UTF-8 | en_US.UTF-8 | f | t | -1 | 1418
6 | 479 | 1 | 1663
16403 | db_xff | 10 | 6 | en_US.UTF-8 | en_US.UTF-8 | f | t | -1 | 1418
6 | 479 | 1 | 1663
1 | template1 | 10 | 6 | en_US.UTF-8 | en_US.UTF-8 | t | t | -1 | 1418
6 | 479 | 1 | 1663
14186 | template0 | 10 | 6 | en_US.UTF-8 | en_US.UTF-8 | t | f | -1 | 1418
6 | 479 | 1 | 1663
16407 | db_xifenfei | 16405 | 6 | en_US.UTF-8 | en_US.UTF-8 | f | t | -1 | 1418
6 | 479 | 1 | 16406
(5 rows)
postgres=# select count(1) from tab_class;
count
-------
407
(1 row)
postgres=# select *from pg_tablespace;
oid | spcname | spcowner | spcacl | spcoptions
-------+--------------+----------+--------+------------
1663 | pg_default | 10 | |
1664 | pg_global | 10 | |
16406 | tbs_xifenfei | 16405 | |
(3 rows)
使用pg_filedump_bath脚本来实现批量恢复
[root@xifenfei tmp]# ./pg_filedump_batch recover --database-oid=14187 \ --output-directory=/data/recovery --pgdata=/var/lib/pgsql/12/data Recover tables in database with oid: 14187 LOG: starting to process table tab_attribute LOG: starting to process table tab_class LOG: starting to process table tab_database LOG: starting to process table tab_namespace LOG: starting to process table tab_tablespace LOG: starting to process table tab_type LOG: starting to process table t_tbs LOG: starting to process table t_xff LOG: starting to process table t_xff2 LOG: starting to process table t_xff3 LOG: starting to process table t_xff4 LOG: starting to process table t_xifenfei Check dumps in /data/recovery
参考数据恢复
[root@xifenfei tmp]# cd /data/recovery/ [root@xifenfei recovery]# ls -ltr total 156 -rw-r--r-- 1 root root 82797 Apr 18 20:35 recovered-14187-tab_attribute.csv -rw-r--r-- 1 root root 31129 Apr 18 20:35 recovered-14187-tab_class.csv -rw-r--r-- 1 root root 343 Apr 18 20:35 recovered-14187-tab_database.csv -rw-r--r-- 1 root root 118 Apr 18 20:35 recovered-14187-tab_namespace.csv -rw-r--r-- 1 root root 50 Apr 18 20:35 recovered-14187-tab_tablespace.csv -rw-r--r-- 1 root root 7907 Apr 18 20:35 recovered-14187-tab_type.csv -rw-r--r-- 1 root root 0 Apr 18 20:35 recovered-14187-t_tbs.csv -rw-r--r-- 1 root root 38 Apr 18 20:35 recovered-14187-t_xff.csv -rw-r--r-- 1 root root 38 Apr 18 20:35 recovered-14187-t_xff2.csv -rw-r--r-- 1 root root 38 Apr 18 20:35 recovered-14187-t_xff3.csv -rw-r--r-- 1 root root 38 Apr 18 20:35 recovered-14187-t_xff4.csv -rw-r--r-- 1 root root 38 Apr 18 20:35 recovered-14187-t_xifenfei.csv [root@xifenfei recovery]# cat recovered-14187-tab_database.csv 14187 postgres 10 6 en_US.UTF-8 en_US.UTF-8 f t -1 14186 479 1 1663 16403 db_xff 10 6 en_US.UTF-8 en_US.UTF-8 f t -1 14186 479 1 1663 1 template1 10 6 en_US.UTF-8 en_US.UTF-8 t t -1 14186 479 1 1663 14186 template0 10 6 en_US.UTF-8 en_US.UTF-8 t f -1 14186 479 1 1663 16407 db_xifenfei 16405 6 en_US.UTF-8 en_US.UTF-8 f t -1 14186 479 1 16406 [root@xifenfei recovery]# cat recovered-14187-tab_class.csv|wc -l 407 [root@xifenfei recovery]# cat recovered-14187-tab_tablespace.csv 1663 pg_default 1664 pg_global 16406 tbs_xifenfei
把pg_class恢复数据导入库中进行对比,证明恢复的数据完全正确
postgres=# COPY tab_class_new FROM '/data/recovery/recovered-14187-tab_class.csv'; COPY 407 postgres=# select count(1) from tab_class; count ------- 407 (1 row) count ------- 407 (1 row) postgres=# select count(1) from tab_class_new; count ------- 407 (1 row) postgres=# select * from tab_class_new postgres-# EXCEPT postgres-# select * from tab_class; oid | relname | relnamespace | reltype | reloftype | relowner | relam | relfilenode | reltablespace | relpages | reltuples | rel allvisible | reltoastrelid | relhasindex | relisshared | relpersistence | relkind -----+---------+--------------+---------+-----------+----------+-------+-------------+---------------+----------+-----------+---- -----------+---------------+-------------+-------------+----------------+--------- (0 rows) postgres=# select * from tab_class postgres-# EXCEPT postgres-# select * from tab_class_new; oid | relname | relnamespace | reltype | reloftype | relowner | relam | relfilenode | reltablespace | relpages | reltuples | rel allvisible | reltoastrelid | relhasindex | relisshared | relpersistence | relkind -----+---------+--------------+---------+-----------+----------+-------+-------------+---------------+----------+-----------+---- -----------+---------------+-------------+-------------+----------------+--------- (0 rows)
通过上述操作证明:
1. 在没有人工列出列类型的情况下实现批量pg_filedump恢复功能
2. 在pg库没有启动的情况下直接解析字典实现恢复功能
3. 实现pg数据库的批量恢复
如果有PostgreSQL的数据库故障,自行无法解决,请联系我们提供专业数据库恢复技术支持:
电话/微信:17813235971 Q Q:107644445
E-Mail:dba@xifenfei.com

加我微信(17813235971)
加我QQ(107644445)

