如果不小心从 pg_class 中删除了 table 那么如何从备份中恢复它?

If a table is dropped from pg_class accidentally then how to restore it from backup?

我不小心从 pg_class 中删除了一个 table,并且我在架构内的不同服务器中有相同的 table。我该如何恢复它?

我试过了

psql -U {user-name} -d {desintation_db} -f {dumpfilename.sql}`

这就是我得到的 -

ERROR:  type "food_ingredients" already exists`
HINT:  A relation has an associated type of the same name, so you must use a name that doesn't conflict with any existing type.`
ERROR:  relation "food_ingredients" does not exist`
ERROR:  syntax error at or near "19411"`
LINE 1: 19411 10405 2074 45.3333333333 0.17550085492131515 NULL NULL...`
ERROR:  relation "food_ingredients" does not exist`

food_ingredients 是我从 pg_class.

中删除的 table

这就是你乱用系统目录的结果。

简单而正确的答案是“从备份中恢复”,但有些东西告诉我这不是您要找的答案。

您可以删除属于 table 的类型、table 上的所有索引、所有约束、toast table 等等,但您可能会忘记丢掉或丢掉不该丢的东西,结果比以前更乱。
而且,table文件会被遗留,很难识别和删除。

尝试重新创建您删除的 pg_class 行会很有吸引力,但您无法使用正确的 oid 创建它,因为您无法直接插入某个 oid 或更新该列。

您可以使用 pg_dumpall 转储整个数据库集群,使用 initdb 创建一个新集群并在那里恢复备份,但这可能会因为数据不一致而失败。

真的,最好是恢复备份。

我能够使用 pg_dirtyread 扩展执行 部分恢复

初始情况是:

relation "messed_table" does not exist`

以下查询为我提供了我删除的值:

SELECT * FROM pg_dirtyread('pg_class'::regclass)
as t(relname name, relnamespace oid, reltype oid, reloftype oid, relowner oid, relam oid, relfilenode oid, reltablespace oid, relpages integer, reltuples real, relallvisible integer, reltoastrelid oid, relhasindex boolean, relisshared boolean, relpersistence "char", relkind "char", relnatts smallint, relchecks smallint, relhasoids boolean, relhaspkey boolean, relhasrules boolean, relhastriggers boolean, relhassubclass boolean, relrowsecurity boolean, relforcerowsecurity boolean, relispopulated boolean, relreplident "char", relispartition boolean, relfrozenxid xid, relminmxid xid, relacl aclitem[], reloptions text[], relpartbound pg_node_tree)
WHERE relname = 'messed_table';

我使用了执行插入的结果:

INSERT INTO pg_class
(relname,relnamespace,reltype,reloftype,relowner,relam,relfilenode,reltablespace,relpages,reltuples,relallvisible,reltoastrelid,relhasindex,relisshared,relpersistence,relkind,relnatts,relchecks,relhasoids,relhaspkey,relhasrules,relhastriggers,relhassubclass,relrowsecurity,relforcerowsecurity,relispopulated,relreplident,relispartition,relfrozenxid,relminmxid,relacl,reloptions,relpartbound)
VALUES('messed_table',16447,17863,0,10,0,17861,0,0,0,0,0,false,false,'p','r',78,0,false,false,false,false,false,false,false,true,'d',false,1129231::text::xid,1::text::xid,null,null,null);

在这个阶段执行一个SELECT * from messed_table返回

catalog is missing 78 attribute(s) for relid 26130

所以我创建了一个新的 table messed_table_copy 与乱七八糟的 table.

具有相同的结构

我使用以下查询将 messed_table_copy table 的 pg_attribute 内容导出到文件:

Copy (SELECT * FROM pg_attribute WHERE attrelid = (SELECT oid from pg_class WHERE relname LIKE 'messed_table_copy') and attnum > 0) To '/tmp/recover.csv' With CSV DELIMITER ',' HEADER;

我把attrelid的值改成了报错信息中指出的relid的值,然后又从文件中导入了数据:

COPY pg_attribute(attrelid,attname,atttypid,attstattarget,attlen,attnum,attndims,attcacheoff,atttypmod,attbyval,attstorage,attalign,attnotnull,atthasdef,attidentity,attisdropped,attislocal,attinhcount,attcollation,attacl,attoptions,attfdwoptions) FROM '/tmp/recover.csv' DELIMITER ',' CSV HEADER;

在这个阶段 SELECT count(*) FROM messed_table 工作但是 SELECT * FROM messed_table 使数据库崩溃并出现以下错误:

server closed the connection unexpectedly
        This probably means the server terminated abnormally
        before or while processing the request.
The connection to the server was lost. Attempting reset: Failed.

执行一些仅指定所有可用列的子集的查询时,我注意到仅选择某些列会发生崩溃。我已经能够恢复大约 90% 的数据,丢失了一些列的内容。祝你好运,记住永远不要再玩 pg_class table。