Поврежденные индексы в 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

Итак, если вы видите эту ошибку, у вас есть два варианта действий:

  1. Вы можете обойти проблему … в данном случае в таблице tags есть дублирующаяся строка с именем chronicillness.

    1. Выполните запрос в Data Explorer для поиска строк: select * from tags where name = 'chronicillness'

    2. Удалите дубликат:

      ./launcher enter app
      rails c
      Tag.find_by(id: ID_YOU_FOUND_IN_DATA_EXPLORER).destroy   
      
  2. Если у вас есть резервная копия базы данных и детали, которыми вы хотели бы поделиться с Питером… поделитесь ими с Питером либо в частном порядке, либо в рассылке PG.

Итак, у меня есть резервная копия PostgreSQL 10, созданная через Discourse. Это будет полезно? Могу ли я просто извлечь часть PostgreSQL из архива и отправить её?

Не уверен… скорее всего, Питеру потребуется, чтобы вы остановили базу данных и скопировали всё содержимое папки, в которой она находится.

Лучший способ узнать наверняка — написать ему по электронной почте.

Конечно, я напишу ему письмо, чтобы разобраться в этом :slight_smile:

NB: Вот что я получил, запустив SQL в Data Explorer:

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

Может быть, между названиями тегов стоит дефис -?
Я вижу здесь два тега: chronicillness и chronic-illness.

Что ж, тогда это и есть проблема… Похоже, вы удаляете 1710. После этого двум темам будет не хватать этого тега.

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

Почему у меня возникает ощущение, что это был гном, который ни с чем не был связан?

Удаление тега привело к появлению новых проблем!

discourse=# REINDEX SCHEMA CONCURRENTLY public;
WARNING:  невозможно выполнить одновременное перестроение недопустимого индекса "public.tags_pkey_ccnew", пропускаем
WARNING:  невозможно выполнить одновременное перестроение недопустимого индекса "public.index_tags_on_name_ccnew", пропускаем
WARNING:  невозможно выполнить одновременное перестроение недопустимого индекса "public.index_tags_on_lower_name_ccnew", пропускаем
WARNING:  невозможно выполнить одновременное перестроение недопустимого индекса "pg_toast.pg_toast_309322_index_ccnew", пропускаем
ERROR:  не удалось создать уникальный индекс "index_tags_on_name_ccnew1"
DETAIL:  Ключ (name)=(time-management) дублируется.

То же исправление :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… вы создали их вручную?

Похоже, они используются при миграции с PostgreSQL 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

РЕДАКТИРОВАНИЕ: информация из документации PostgreSQL

Рекомендуемый способ восстановления в таких случаях — удалить невалидный индекс и снова попытаться выполнить REINDEX CONCURRENTLY. Конкурентный индекс, созданный в процессе обработки, имеет имя, оканчивающееся на суффикс ccnew, или ccold, если это старое определение индекса, которое нам не удалось удалить. Неверные индексы можно удалить с помощью DROP INDEX, включая невалидные TOAST-индексы.

Ой… индексы уже добавлены к таблице?

Кажется, вы можете перечислить индексы таблицы с помощью Data Explorer.

Если нужные индексы уже есть, то вы можете просто удалить эти проблемные индексы.

Дайте мне проверить. Я отчитаюсь.

Итак, похоже, что индексы существуют

Для проблемных индексов также существуют дубликаты с добавленными суффиксами ccnew или ccnew1:

Я не знаю, как проверить, корректны ли эти индексы, но если их удаление (nuking) возможно, я с радостью удалю их и перестрою индексы заново.

РЕДАКТИРОВАНИЕ: сработает ли DROP INDEX, как предложено здесь?

Да, удалите их все… не знаю, как они туда попали… Используйте DROP INDEX.

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