Postgresql

使用“壓縮數據已損壞”錯誤轉儲數據庫

  • February 1, 2016

pg_dump用來轉儲一個大型(396 GB)PostgreSQL 數據庫:

pg_dump --clean --create mydatabase

執行一天后,一條語句失敗ERROR: compressed data is corruptpg_dump退出。

100% 的數據完整性不是我的首要任務。這可能只是一個損壞的行阻止我移動或備份一個需要數週時間才能創建的數據庫。輸掉那一排我很好。

有沒有辦法創建一個忽略此類數據錯誤的轉儲?我在pg_dump文件中什麼也沒找到。

如果沒有,如何查找並刪除表中所有損壞的行?其他表中的行指向它們,也需要刪除。

根據消息來源中的 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'

ctid是一個偽列,以 的形式指示行的物理位置(page,index in page),因此這會將內容按其順序轉儲到數據文件中。

此 COPY 命令在到達有問題的行時應該會出錯,但此時它應該已經流式傳輸了一些輸出(需要在實踐中確認)。此輸出的末尾應指示ctid數據未損壞的時間。

從這裡開始ctid,應該可以用二分法來查明有問題的行,執行查詢,例如

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

的點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$;

並通過它執行所有行以找到ctid損壞的行。

select ctid from table where chk(table);

引用自:https://dba.stackexchange.com/questions/127846