3.1.0.beta4 업그레이드 중 PG::UniqueViolation 문제 발생

3.1.0.beta4로 업그레이드하는 동안 다음과 같은 오류가 발생했습니다.

I, [2023-04-19T00:02:26.057232 #1]  INFO -- : > cd /var/www/discourse && su discourse -c 'LOAD_PLUGINS=0 bundle exec rake plugin:pull_compatible_all'
I, [2023-04-19T00:02:27.340128 #1]  INFO -- : discourse-adplugin is already at latest compatible version
discourse-cakeday is already at latest compatible version
discourse-formatting-toolbar is already at latest compatible version
discourse-whos-online is already at latest compatible version
docker_manager is already at latest compatible version
vbulletin-bbcode is already at latest compatible version

I, [2023-04-19T00:02:27.340368 #1]  INFO -- : > cd /var/www/discourse && su discourse -c 'bundle exec rake db:migrate'
2023-04-19 00:02:30.080 UTC [634] discourse@discourse ERROR:  duplicate key value violates unique constraint "index_users_on_username"
2023-04-19 00:02:30.080 UTC [634] discourse@discourse DETAIL:  Key (username)=(xxx) already exists.
2023-04-19 00:02:30.080 UTC [634] discourse@discourse STATEMENT:  UPDATE users SET password_algorithm = '$pbkdf2-sha256$i=64000,l=32$'
	WHERE id IN (
	  SELECT id FROM users
	  WHERE users.password_hash IS NOT NULL
	  AND users.password_algorithm IS NULL
	  LIMIT 5000
	)
	
rake aborted!
StandardError: An error has occurred, all later migrations canceled:

PG::UniqueViolation: ERROR:  duplicate key value violates unique constraint "index_users_on_username"
DETAIL:  Key (username)=(xxx) already exists.

중복된 사용자를 수정한 후에도 다시 새로운 중복 오류가 발생합니다.

discourse=# REINDEX TABLE users;
ERROR:  could not create unique index "index_users_on_username_lower"
DETAIL:  Key (username_lower)=(mhm) is duplicated.
discourse=# REINDEX TABLE users;
ERROR:  could not create unique index "index_users_on_username_lower"
DETAIL:  Key (username_lower)=(ahmedhafez) is duplicated.
CONTEXT:  parallel worker
discourse=# REINDEX TABLE users;
ERROR:  could not create unique index "index_users_on_username_lower"
DETAIL:  Key (username_lower)=(hany) is duplicated.
discourse=# REINDEX TABLE users;
ERROR:  could not create unique index "index_users_on_username_lower"
DETAIL:  Key (username_lower)=(eng_ali) is duplicated.
CONTEXT:  parallel worker
discourse=# REINDEX TABLE users;
ERROR:  could not create unique index "index_users_on_username_lower"
DETAIL:  Key (username_lower)=(saad_saad) is duplicated.
discourse=# REINDEX TABLE users;
ERROR:  could not create unique index "index_users_on_username_lower"
DETAIL:  Key (username_lower)=(eng_ali) is duplicated.
CONTEXT:  parallel worker
discourse=# REINDEX TABLE users;
ERROR:  could not create unique index "index_users_on_username_lower"
DETAIL:  Key (username_lower)=(mostafa11) is duplicated.
CONTEXT:  parallel worker

손상된 인덱스이거나 어떤 방식으로든 대소문자가 다른 동일한 사용자명으로 계정을 생성할 수 있었던 경우일 수 있습니다.

아래 명령어로 기존 컨테이너를 시작할 수 있습니다.

./launcher start app

그 다음 테이블을 다시 인덱싱하여 어떤 사용자가 손상되었는지 확인하고, 이를 수정한 후 인덱스가 다시 빌드될 때까지 이 과정을 반복해 보세요.

답장 주셔서 감사합니다.

네, 앱 시작/진입은 가능합니다. 또한 조언해 주신 대로 진행 중입니다.

discourse=# REINDEX TABLE users;
ERROR:  could not create unique index "index_users_on_username_lower"
DETAIL:  Key (username_lower)=(mostafa11) is duplicated.

문제는 중복 데이터가 계속 발생한다는 점입니다. 사용자는 30만 명 이상입니다.
중복 데이터의 수를 확인하거나 모든 중복 항목을 나열하는 방법이 있을까요?

수정 작업은 다음과 같이 username_lower 끝에 숫자를 붙이는 방식으로 진행했습니다.

UPDATE users SET username_lower = 'xxx' WHERE id = xxx;

username_lower와 일치하도록 username 컬럼도 업데이트해야 하나요? 중복 항목을 자동으로 수정하는 더 빠른 방법이 있을까요?

현재 제 웹사이트가 오프라인 상태이므로, 도움이 절실합니다.

그런 방법은 없는 것으로 알고 있습니다. 그런 일은 일어나지 않아야 한다고 생각합니다. 어떤 버전에서 업그레이드하고 계신가요?

아마도 username != username_lower인 사용자를 검색해 볼 수 있을 것입니다.

앱을 시작했는데도 여전히 다운된 상태인가요?

아니요. 사용자 이름에 대소문자가 섞여 있어도 괜찮지만, 같은 글자로 이루어진 사용자 이름이 두 개 존재하는 것은 원치 않습니다.

Joe와 joe가 모두 존재하는 그런 경우인가요? 그렇다면 그들을 찾을 수 있는 쿼리가 있을 것 같지만, 바로 어떻게 해야 하는지는 모르겠습니다.

Jay, 감사합니다.
재빌드하여 웹사이트를 다시 온라인으로 복구했습니다.

먼저, 제안을 해주신 대로 해결 방법은 재인덱싱, 수정, 그리고 완료될 때까지 반복하는 것입니다. 다음 명령어를 사용하여 중복된 항목이 몇 개인지 확인했습니다.

SELECT username_lower, count(*) from users GROUP by username_lower HAVING count(*) > 1;

결과가 0으로 나왔습니다.

물론 중복된 항목이 많이 있었고, 그 수가 몇 개인지 알고 싶었습니다. 그래서 쿼리를 약간 조정했습니다:

SELECT username_lower, count(username) from users GROUP by username_lower HAVING count(username) > 1;

이렇게 하니 약 50개의 중복 항목이 반환되었고, 이를 수정한 후 재인덱싱 및 재빌드가 성공적으로 완료되었습니다.

좋아요! 해결하신 것 같아 기쁩니다. 같은 문제를 겪는 다른 분들에게도 당신의 메모가 큰 도움이 될 거예요.

다른 분들이 당신의 SQL을 더 쉽게 복사/붙여넣을 수 있도록 게시글을 수정해 두었습니다.