PG12 の破損インデックスの修復方法について

再度スレッドをアップさせてしまい申し訳ありません。非常に奇妙なエラーが発生しました。

discourse=# REINDEX SCHEMA CONCURRENTLY public;
ERROR:  could not create unique index "index_tags_on_name_ccnew"
DETAIL:  Key (name)=(chronicillness) is duplicated.

@riking さんが上記で提案された解決策で修正できるだろうとは思うのですが、私のケースに合わせて構文を修正する方法がわかりません。:frowning:

参照:

https://twitter.com/petervgeoghegan/status/1264325695997538304?s=20

https://twitter.com/petervgeoghegan/status/1264404749899534338?s=20

このエラーが表示された場合、以下の 2 つの対応が可能です。

  1. 問題の回避策を試す(この場合、tags テーブルに chronicillness という名前の重複行が存在します)

    1. データエクスプローアで以下のクエリを実行し、該当する行を検索します。

      select * from tags where name = 'chronicillness'
      
    2. 重複行を削除します。

      ./launcher enter app
      rails c
      Tag.find_by(id: ID_YOU_FOUND_IN_DATA_EXPLORER).destroy
      
  2. データベースのバックアップがあり、Peter に共有したい詳細情報がある場合は、Peter に直接、または PG メーリングリストで共有してください。

Discourse によって生成された PostgreSQL 10 のバックアップがあります。これは役に立ちますか?アーカイブから PostgreSQL の部分だけを抽出して送ればよいでしょうか?

確信はありませんが、ピーター氏が必要とする可能性が高いのは、データベースを停止し、データベースを含むフォルダの内容全体をコピーすることです。

確認する最善の方法は、彼にメールすることです。

はい、彼にメールを送ってこの件を解決しましょう :slight_smile:

参考情報:データエクスプローラーで SQL を実行した際に得られた結果です。

id name topic_count created_at updated_at pm_topic_count target_tag
1710 chronicillness 2 2019-12-03T17:49:17.395Z 2019-12-03T17:49:17.395Z 0 NULL

次のコードで問題は解決しますか?

Tag.find_by(id: 1710).destroy

ああ……インデックスは LOWER(name) にかかっていますね。

クエリを以下のように実行してください:

select * from tags where name ilike 'chronicillness'

これで 2 行が取得されるはずです。

select * from tags where name ilike 'chronicillness'
id name topic_count created_at updated_at pm_topic_count target_tag
329 chronicillness 12 2017-08-22T00:17:38.824Z 2017-08-22T00:17:38.824Z 0 NULL
1710 chronicillness 2 2019-12-03T17:49:17.395Z 2019-12-03T17:49:17.395Z 0 NULL

タグ名の間に - が入っている可能性がありますか?
ここでは chronicillnesschronic-illness という 2 つのタグを確認しました。

なるほど、それが問題ですね……たぶん 1710 を削除するのでしょう。そうすると、そのタグが付いたトピックが 2 つなくなることになります。

#<Tag:0x00005607bb92cf48
 id: 1710,
 name: "chronicillness",
 topic_count: 0,
 created_at: 2019-12-03 17:49:17 UTC +00:00,
 updated_at: 2019-12-03 17:49:17 UTC +00:00,
 pm_topic_count: 0,
 target_tag_id: nil>

なぜか、何にも関連付けられていないドワーフがいたような気がするのですが?

タグを削除したら、さらに問題が発生しました!

discourse=# REINDEX SCHEMA CONCURRENTLY public;
WARNING:  cannot reindex invalid index "public.tags_pkey_ccnew" concurrently, skipping
WARNING:  cannot reindex invalid index "public.index_tags_on_name_ccnew" concurrently, skipping
WARNING:  cannot reindex invalid index "public.index_tags_on_lower_name_ccnew" concurrently, skipping
WARNING:  cannot reindex invalid index "pg_toast.pg_toast_309322_index_ccnew" concurrently, skipping
ERROR:  could not create unique index "index_tags_on_name_ccnew1"
DETAIL:  Key (name)=(time-management) is duplicated.

同じ修正です :slight_smile: 手順を繰り返してください。

それが私がやっていたことです。でも、その警告は大丈夫ですか?気にしなくていいですよね?

はい、すべての警告は正しいです。インデックスが破損しているため、まず修正が必要です。

すべてのコピーキャットは削除され、再インデックス作成中はこれらの警告のみが残っています:

discourse=# REINDEX SCHEMA CONCURRENTLY public;
WARNING:  cannot reindex invalid index "public.tags_pkey_ccnew" concurrently, skipping
WARNING:  cannot reindex invalid index "public.index_tags_on_name_ccnew" concurrently, skipping
WARNING:  cannot reindex invalid index "public.index_tags_on_lower_name_ccnew" concurrently, skipping
WARNING:  cannot reindex invalid index "public.tags_pkey_ccnew1" concurrently, skipping
WARNING:  cannot reindex invalid index "public.index_tags_on_name_ccnew1" concurrently, skipping
WARNING:  cannot reindex invalid index "public.index_tags_on_lower_name_ccnew1" concurrently, skipping
WARNING:  cannot reindex invalid index "pg_toast.pg_toast_309322_index_ccnew" concurrently, skipping
WARNING:  cannot reindex invalid index "pg_toast.pg_toast_309322_index_ccnew1" concurrently, skipping
REINDEX

これらの警告を解消するために何か対応すべきでしょうか、それともこれらをそのまま受け入れる必要がありますか。

これは私には混乱しています……「ccnew」で終わるインデックス名は存在しません。これらは手動で作成されたのでしょうか?

Postgres 10 から 12 への移行時に使用されているものだと思います。インデックスに問題が発生したユーザーのほとんどでこれらを確認しています。例:
https://meta.discourse.org/t/postgresql-12-update/151236/208?u=itsbhanusharma

https://meta.discourse.org/t/postgresql-12-update/151236/237?u=itsbhanusharma

編集:Postgres 自体からの情報です

このような場合の推奨される復旧方法は、無効なインデックスを削除し、REINDEX CONCURRENTLY を再実行することです。処理中に作成された並行インデックスの名前は、接尾辞 ccnew で終わるか、削除に失敗した古いインデックス定義の場合は ccold で終わります。無効なインデックス(無効な TOAST インデックスを含む)は、DROP INDEX を使用して削除できます。

おっと…適切なインデックスもすでにテーブルに存在しますか?

データエクスプローアを使ってテーブルのインデックスをリストできると思います。

もし正しいインデックスが既に存在する場合は、問題のあるインデックスは削除して構いません。

確認します。後で報告します。

つまり、インデックスは存在しているようです。

問題のあるインデックスには、ccnew または ccnew1 が追加された重複インデックスも存在します。

それらのインデックスが有効かどうかを確認する方法はわかりませんが、削除して再インデックス化することが可能であれば、喜んで実行します。

編集:こちらで提案されている DROP INDEX は機能しますか?

はい、すべて削除しましょう……どのようにそこに入ったかはわかりませんが……DROP INDEXを使用するのが正解です。

./launcher enter app
rails c
DB.exec('drop index tags_pkey_ccnew1')