PostgreSQL数据迁移过程中遇到Toast表损坏和缺少Chunk Number错误

问题描述 投票:0回答:1

版本 - PostgreSQL 10.21,由 Visual C++ build 1800 编译,64 位

平台 - Windows

将数据从 PostgreSQL 10.21 迁移到 14.7 时,我们在转储过程中遇到与表损坏相关的问题,导致错误消息“无法打开文件“base/16510/37857”:没有这样的文件或目录。”

错误:无法打开文件“base/16510/37857”:没有这样的文件或目录

检查“relfilenode”的“relkind”后,确定类型为toast table。在尝试恢复数据时,我们最初尝试截断 toast 表,但遇到了阻止成功截断的错误。作为解决方法,我们在目录“base/16510”下创建了一个名为“37857”的新空文件。然而,这导致了一个新错误:“pg_toast_37722 中的 toast 值 15977662 缺少块编号 0。”

错误:pg_toast_37722 中的 toast 值 15977662 缺少块编号 0

ProdDB=# select count(*) from prrhtab;
 count
--------
 232966
(1 row)

ProdDB=# select * from prrhtab;
ERROR:  could not open file "base/16510/37857": No such file or directory
ProdDB=# select relname, relkind from pg_class where relfilenode=37857;
    relname     | relkind
----------------+---------
 pg_toast_37722 | t
(1 row)

ProdDB=# select * from pg_toast.pg_toast_37722;
ERROR:  could not open file "base/16510/37857": No such file or directory
ProdDB=# select count(*) from pg_toast.pg_toast_37722;
ERROR:  could not open file "base/16510/37857": No such file or directory

ProdDB=# truncate table pg_toast.pg_toast_37722;
ERROR:  "pg_toast_37722" is not a table

ProdDB=# select count(*) from pg_toast.pg_toast_37722;
 count
-------
     0
(1 row)

ProdDB=# select * from prrhtab;
ERROR:  could not read block 2635 in file "base/16510/37857": read only 0 of 8192 bytes
ProdDB=# reindex table prrhtab;
REINDEX
ProdDB=# select * from prrhtab;
ERROR:  missing chunk number 0 for toast value 15977662 in pg_toast_37722

ProdDB=# select count(*) from prrhtab;
 count
--------
 232966
(1 row)


ProdDB=# select * from prrhtab order by id desc limit 1;
    id   
---------
 1177027 
(1 row)

为了解决此问题,我们继续逐一删除损坏的行,结果,“缺少块编号”错误不再发生。

不幸的是,我们没有表损坏发生之前的备份。虽然我们能够使用上述方法继续进行迁移,但我们不确定是否有其他方法可以解决此问题而不丢失任何数据。此外,逐一检查行以解决“缺少块编号”错误的过程似乎效率不高。因此,我们将不胜感激任何有关最佳解决方案的建议以及可能的原因,以便将来避免类似问题。

参考了下面的线程,但是在处理较高的行数时似乎很耗时。

postgresql error-handling migration upgrade corruption
1个回答
0
投票

您以正确的方式解决了问题。

什么可能帮助您找到有问题的行:

DO
$$DECLARE
   v_pk bigint;  -- or whatever type your primary key is
   v_t text;
BEGIN
   FOR pk IN SELECT id FROM prrhtab LOOP
      BEGIN
         SELECT prrhtab::text INTO v_t FROM prrhtab WHERE id = v_pk;
      EXCEPTION
         WHEN OTHERS THEN
            RAISE NOTICE 'Broken row with id = %', v_pk;  -- or go ahead and delete it
      END;
   END LOOP;
END;$$;
© www.soinside.com 2019 - 2024. All rights reserved.