기본적으로 PostgreSQL은 유니크 인덱스를 강제하기 위해 튜플의 고유성을 검사할 때 NULL을 서로 다른 값으로 간주합니다. 이로 인해 레이스 컨디션(race condition)으로 인해 { 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;)
한 클라이언트는 백업 복구를 시도하고 있었습니다(자신들이 셀프 호스팅을 하고 있었고, 자신의 지식 수준을 넘어서는 것들을 시도하고 있었던 것 같습니다 ). 또 다른 클라이언트는 커스텀 플러그인 개발을 위해 스테이징 사이트를 설정해 달라고 요청했고, 우리는 CDCK 호스팅에서 백업을 가져왔습니다.
일반적으로 백업 메타데이터에 내장된 버전 관리 메커니즘은 문제가 발생하기 전에 능동적으로 이를 파악하는 데 매우 잘 작동하지만, 이러한 유형의 상황*은 지뢰와 같습니다
(* 사실, 마이그레이션 버전 관리가 다루지 않는 다른 유일한 경우는 더 오래된 날짜 스탬프를 가진 마이그레이션이 메인에 삽입되는 경우인데, 좀 더 들어가 보겠습니다)
문제가 이미 해결된 것을 알 수 있지만, 실사용 경험을 하나 더 공유하겠습니다. Docker를 사용하여 로컬에서 개발 환경을 설정하는 과정 중, Discourse 호스팅 인스턴스에서 생성된 백업 파일을 복원하려고 할 때 이 문제가 발생했습니다. Discourse 호스팅에서는 PostgreSQL 15를 사용하는 반면, 개발 환경에서는 13을 사용하는 것 같습니다?