转储具有“压缩数据已损坏”错误的数据库

kon*_*ify 6 postgresql backup postgresql-9.3 pg-dump

我正在使用pg_dump转储大型(396 GB)PostgreSQL 数据库:

pg_dump --clean --create mydatabase
Run Code Online (Sandbox Code Playgroud)

运行一天后,语句失败ERROR: compressed data is corruptpg_dump退出。

100% 的数据完整性不是我的首要任务。这可能只是一个断行阻止我移动或备份一个需要数周时间创建的数据库。输了那行我没问题。

有什么方法可以创建忽略此类数据错误的转储?我在pg_dump文档中什么也没找到。

如果没有,如何查找并删除表中所有损坏的行?其他表中的行指向它们,也需要删除。

Dan*_*ité 5

根据消息来源中的 grep,此错误

错误:压缩数据已损坏

在 LZ 压缩的 TOAST 值解压失败的情况下发生。

http://doxygen.postgresql.org/tuptoaster_8c.html#abcb4cc32d19cd5f89e27aeb7e7369fa8

在行级存储中,大值存储为指向pg_toast包含实际数据的模式中的表的指针。

如何查找和删除表中所有损坏的行?

假设你知道它是什么表(如果不知道,迭代这些表,从最大的列开始),可能有用的东西是:

COPY (select ctid,* FROM tablename ORDER BY ctid) TO '/path/to/file'
Run Code Online (Sandbox Code Playgroud)

ctid是一个伪列,以 的形式指示行的物理位置(page,index in page),因此这将按顺序将内容转储到数据文件中。

当这个 COPY 命令到达有问题的行时,它应该会出错,但此时它应该已经传输了一些输出(在实践中得到确认)。此输出的结尾应指示ctid数据未损坏的时间。

从这里开始ctid,应该可以使用二分法确定违规行,运行查询,例如

SELECT ctid,length(t.*::text) FROM table t WHERE ctid>='(?,?)' ORDER BY ctid LIMIT 10
Run Code Online (Sandbox Code Playgroud)

关键length(t.*::text)是它必须提取所有解压缩的数据,而不是,例如count(*).

找到损坏的行后,DELETE FROM table WHERE ctid='(?,?)'可用于删除它们。

请注意,如果 VACUUM 正在处理此表,则可能会更改ctid某些行的 。关闭 autovacuum 或在事务内完成所有工作应该可以避免该潜在问题。


编辑:对错误消息的网络搜索显示了Robert Berry的一篇博客文章,提出了一种似乎没有上述方法那么挑剔的方法。本质上,创建这个函数:

create function chk(anyelement)
  returns bool 
  language plpgsql as $f$ 
    declare t text; 
    begin t := $1; 
      return false; 
      exception when others then return true; 
    end; 
  $f$;
Run Code Online (Sandbox Code Playgroud)

并通过它运行所有行以找到ctid损坏的行。

select ctid from table where chk(table);
Run Code Online (Sandbox Code Playgroud)