我正试图从以下一些数据库中恢复/拯救数据库:
-
我在
PGDATA/base
(/var/lib/postgresql/9.6/main/base/
)中有所有最近的文件,但我没有完整的/var/lib/postgresql/9.6/main/
-
我有所有来自旧备份(没有太大不同)转储的文件,我在新安装的PostgreSQL-9.6中恢复了这些文件。
-
我有很多从硬盘驱动器(从
ddrescue
)中拯救的文件,我得到了数千个没有名字的文件(有一个"#",然后有一个数字,并且在丢失+找到的目录中),所以,例如:- 我有
pg_class
文件 - 我有
pg_clog
目录和0000
文件
- 我有
编辑:
可能我有pg_xlog
的内容,但我没有文件的名称。我有5个文件大小16777216字节:
#288294 (date 2019-04-01)
#288287 (date 2019-05-14)
#288293 (date 2019-07-02)
#261307 (date 2019-11-27)
#270185 (date 2020-01-28)
我的旧垃圾箱是2019-04-23,所以第一个可能是一样的吗?
所以我的下一步是尝试用pg_xlogdump
读取这些文件和/或尝试用这些名称文件命名它们(以开头00000001000000000000000A
,并将它们放在新的pg_xlog
目录中,我看到命名它们的系统文件可能是?)。我还意识到最后一个有硬盘崩溃当天的日期,所以我有最后一个。
我从硬盘驱动器(损坏)中拯救的PGDATA/base
目录包含目录1
、12406
、12407
和37972
,其中有很多文件。我向pg_filedump -fi
确认我的更新数据存储在目录37972
中的文件中。
相同(但旧的)数据存储在恢复转储中目录PGDATA/base/16387
中的文件中。
我试图直接将文件从一个复制到另一个,在旧数据库上混合更新的数据,但不起作用。在解决了权限错误后,我可以以这种方式进入"弗兰肯斯坦"数据库:
postgres@host:~$ postgres --single -P -D /var/lib/postgresql/9.6/main/ dbname
我试着做一些事情,比如重新索引,但我得到了这个错误:
PostgreSQL stand-alone backend 9.6.16
backend> reindex system dbname;
ERROR: could not access status of transaction 136889
DETAIL: Could not read from file "pg_subtrans/0002" at offset 16384: Success.
CONTEXT: while checking uniqueness of tuple (1,7) in relation "pg_toast_2619"
STATEMENT: reindex system dbname;
当然,pg_subtrans/0002
文件是"弗兰肯斯坦"的一部分,不是一个好的文件(因为我还没有找到它,不是用那个名字),所以我尝试:先复制另一个看起来相似的文件,然后用dd
生成8192个零到那个文件,在这两种情况下,我都会得到相同的错误(如果文件不存在,就得到DETAIL: Could not open file "pg_subtrans/0002": No such file or directory.
)。不管怎样,我不知道那个文件应该是什么。你认为我可以从其他文件中获取数据吗?或者我可以用一些工具找到丢失的文件吗?因此,对于目录pg_subtrans/0000
中的另一个文件,pg_filedump
显示为空。
额外注意:我发现了这篇有用的博客文章,其中谈到了使用pg_filedump
、pg_class
的文件、reindex system
和其他工具从刚刚拯救的文件中恢复,但我很难理解如何将其适应我的具体而简单的问题(我认为我的问题更容易,因为我有一个转储):https://www.commandprompt.com/blog/recovering_a_lost-and-found_database/
经过4个部分:之后,我们终于完全恢复了基于PGDATA/base/37972
目录的数据库
-
检查和";greping";与
pg_filedump -fi
对应的文件每个表。致";greping";我们做剧本更容易。#!/bin/bash for filename in ./*; do echo "$filename" pg_filedump -fi "$filename"|grep "$1" done
注意:仅适用于小字符串
-
执行伟大的工具
pg_filedump -D
。-D
是一个新的选项(来自postgresql-filedump
版本≥10),使用给定的逗号分隔的类型列表来解码元组。因为我们制作了数据库,所以我们知道类型;只是";需要给出一个以逗号分隔的与表相关的类型列表。我写了";只是";因为在某些情况下可能会有点复杂。我们的一个表需要这种命令:
pg_filedump -D text,text,text,text,text,text,text,text,timestamp,text,text,text,text,int,text,text,int,text,int,text,text,text,text,text,text,text,text,text,text,int,int,int,int,int,int,int,int,text,int,int 38246 | grep COPY > restored_table1.txt
来自pg_filedump -D
手册:
支持的类型:
-
bigint
-
双串行
-
bool
-
字符
-
charN—char(n)
-
日期
-
浮动
-
float4
-
float8
-
int
-
json
-
macaddr
-
名称
-
oid
-
真实
-
串行
-
smallint
-
小型串行
-
文本
-
时间
-
时间戳
-
timetz
-
uuid
-
varchar
-
varcharN—varchar(n)
-
xid
-
xml
-
~--忽略元组中剩下的所有属性
对我们来说,所有这些
text
都是类型字符可变的(255),但varcharN
对我们不起作用,所以经过其他测试,我们最终将其更改为text
。对我们来说,
timestamp
是带时区的时间戳类型,但timetz
对我们不起作用,所以在其他测试之后,我们最终将其更改为timestamp
,并选择丢失时区数据。这种变化非常适合这张桌子。
其他表格要简单得多:
pg_filedump -D int,date,int,text 38183 | grep COPY > restored_table2.txt
-
因为我们得到的只是";生的";我们必须将数据重新格式化为CSV格式。因此,我们制作了一个从
pg_filedump -D
输出到CSV格式的python程序。 -
我们将每个CSV插入PostgreSQL(在再次创建每个空表之后):
COPY scheme."table2"(id_comentari,id_observacio,text,data,id_usuari,text_old) FROM '<path>/table2.csv' DELIMITER '|' CSV HEADER;
我希望这能帮助其他人:)
这是注定的。如果没有pg_xlog
和(特别是)pg_clog
中的信息,您就无法取回信息。
一个知识渊博的取证专家可能能够挽救你的一些数据,但这不是一个简单的过程。