По умолчанию при проверке уникальности кортежа для обеспечения уникальности индекса PostgreSQL считает значения NULL различными. Из-за этого из-за условий гонки могли ошибочно создаваться несколько записей с { identifier: "rails_env", target: nil }. Это приводило к ошибкам во время выполнения.
Как это решается?
Удалить существующий индекс и создать его заново с опцией NULLS NOT DISTINCT.
Проблема
Однако NULLS NOT DISTINCT был введён в версии Postgres 15 beta2. Текущая версия Postgres при стандартной установке — Postgres 13, которая не поддерживает эту функцию.
Последствия
это изменение не окажет никакого эффекта на PG13, поскольку NULLS NOT DISTINCT будет игнорироваться (источник)
попытка восстановить резервную копию с сервера PG15 на сервер PG13 завершится ошибкой:
ERROR: syntax error at or near "NULLS"
LINE 1: ...m_check_trackers USING btree (identifier, target) NULLS NOT ...
^
EXCEPTION: psql failed: ^
/var/www/discourse/lib/backup_restore/database_restorer.rb:92:in `restore_dump'
(полная строка: CREATE UNIQUE INDEX index_problem_check_trackers_on_identifier_and_target ON public.problem_check_trackers USING btree (identifier, target) NULLS NOT DISTINCT;)
Ну, я не могу говорить за других и не знаю, действительно ли я представляю большинство (скорее всего, нет), но я столкнулся с этим дважды в течение 3 дней после внесения этого изменения…
Так что обходное решение (и откат!) было бы очень кстати.
Теперь, когда у нас есть обходной путь, который должен работать и в PG15, мы сможем убрать NULLS NOT DISTINCT.
Из любопытства, что вы делали, что потребовалось восстановить резервную копию PG15 на PG13? (На задачу выше это не повлияет, просто пытаюсь понять, что происходит «в реальной жизни» насколько это возможно.)
У нас был один клиент, который пытался восстановить резервную копию (кажется, у них был свой хостинг, и они пытались делать вещи, выходящие за рамки их компетенции ), а у нас был другой клиент, который попросил нас настроить тестовый сайт для разработки кастомных плагинов, и мы взяли резервную копию с хостинга CDCK.
В целом встроенный механизм версионирования в метаданных резервных копий работает отлично, позволяя заранее определить, произойдёт ли сбой или нет, но такие ситуации* — это как мины
(* На самом деле, единственное другое, что я могу вспомнить, что не охвачено версионированием миграций, — это когда миграция с более старой датой внедряется в основную ветку, но я отвлекаюсь)
Я вижу, что проблема уже решена, но для полноты картины добавлю свой опыт: у меня возникла эта проблема при попытке восстановить резервную копию, созданную на хостинге Discourse, в локальный dev-контейнер, настроенный через Docker в рамках подготовки среды разработки. Похоже, что на хостинге Discourse используется PostgreSQL 15, а в среде разработки — 13?
Да, это корень проблемы. Нам нужно обновить наш контейнер с открытым исходным кодом до версии 15. Мы займемся этим в течение следующих нескольких месяцев.