我如何修复了一个来自postgres的表

我写这篇帖子是关于一个导致我每日备份失败的 PostgreSQL 表缺失块错误。我设法解决了这个问题,并想在此列出我使用的方法,以防它能帮助到其他遇到此问题的人。这绝不是解决 PostgreSQL 缺失块错误的正确指南或专业说明,因为我不是专家,而且是在不太了解的情况下进行的,但最终奏效了。

我备份时遇到的错误:

pg_dump: error: Dumping the contents of table "stylesheet_cache" failed: PQgetResult() failed.
pg_dump: error: Error message from server: ERROR:  missing chunk number 0 for toast value 1903804 in pg_toast_22663
pg_dump: error: The command was: COPY public.stylesheet_cache (id, target, digest, content, created_at, updated_at, theme_id, source_map) TO stdout;

所以问题出在 stylesheet_cache 表上,错误是:ERROR: missing chunk number 0 for toast value 1903804 in pg_toast_22663。

我使用的是 Discourse in Docker,我所做的如下:

ssh into the server
cd /path/to/discourse
./launcher rebuild app
su postgres -c "psql discourse"

进入 PostgreSQL 后,我尝试 REINDEX 表,希望能解决问题。

discourse=# select reltoastrelid::regclass from pg_class where relname = 'stylesheet_cache';
      reltoastrelid
-------------------------
 pg_toast.pg_toast_18396
(1 row)
REINDEX table stylesheet_cache;
REINDEX table pg_toast.pg_toast_18396;
VACUUM analyze stylesheet_cache;

再次尝试备份,仍然失败,所以我不得不继续寻找损坏。

我使用以下命令计算了表中的总行数:

select count(*) from stylesheet_cache;

我得到了 2260 行的计数。

我开始寻找损坏的确切行并删除它,我假设 stylesheet_cache 并不是一个会真正破坏我整个数据库的东西。正如我提到的,我不是专家,所以也许我冒了太大的风险,请在执行此操作时小心,因为你可能会弄乱你的数据库。

我使用了 LIMIT 和 OFFSET 查询来查找损坏的行:

select * from stylesheet_cache order by id limit 100 offset 0;

我调整了 offset 和 limit,直到出现“Missing chunk…”错误,然后缩小范围到 LIMIT 1 和 offset 损坏的行。在我的例子中,有 5 行损坏。

你可以使用一个 shell 脚本来更轻松地找到行,我选择了手动方式,这花费了一些时间,但你可以使用这个:

#!/bin/sh
j=0
while [ $j -lt 2260 ]
do
  psql -U postgres -d discourse -c "SELECT * FROM stylesheet_cache LIMIT 1 offset $j" >/dev/null || echo $j
  j=$(($j+1))
done

我使用以下命令查找损坏行的 ID:

select id from stylesheet_cache order by id limit 1 offset 450;

id

----

11498

所以我的损坏行的 ID 是 11498。
我使用以下命令删除了该行:

delete from stylesheet_cache where id = 11498;

删除损坏的行后,我再次 REINDEX:

REINDEX table stylesheet_cache;
REINDEX table pg_toast.pg_toast_40948;
VACUUM analyze stylesheet_cache;

然后再次尝试备份,这次成功了。我参考了这份 PostgreSQL 恢复说明:Postgres error: Missing chunk 0 for toast value in pg_toast · GitHub

免责声明:这不是专家意见,因此如果你遇到类似的缺失块损坏并尝试修复它们,请谨慎操作。

3 个赞