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 を 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;

オフセットとリミットを調整して「Missing chunk…」エラーが発生するまで試行し、その後 LIMIT 1 と、破損した行のオフセットに絞り込みました。私の場合は 5 行が破損していました。

より少ない労力で行を見つけるために sh スクリプトを使用することもできます。私は手動で行いましたが、時間がかかりましたが、これを使用できます。

#!/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