Postgres가 이미 사용 된 PK 값을 생성하는 이유는 무엇입니까?


20

Django를 사용하고 있으며 가끔씩이 오류가 발생합니다.

IntegrityError : 중복 키 값이 고유 제한 조건 "myapp_mymodel_pkey"을 위반합니다
. 세부 사항 : 키 (id) = (1)이 이미 존재합니다.

내 Postgres 데이터베이스에는 실제로 기본 키가 1 인 myapp_mymodel 객체가 있습니다.

Postgres가 기본 키를 다시 사용하려고하는 이유는 무엇입니까? 또는 이것이 내 응용 프로그램 (또는 Django의 ORM)으로 인해 발생했을 가능성이 큽니까?

이 문제는 지금 막 3 회 이상 발생했습니다. 내가 발견 한 것은이 때이다 않습니다 하지 다시 다음, 그것은 주어진 테이블에 대한 행에 한 번 이상 발생 발생합니다. 모든 테이블에 대해 며칠 동안 완전히 중지되기 전에 발생하며 테이블이 발생할 때 테이블 당 최소 1 분 정도 발생하며 간헐적으로 만 발생합니다 (모든 테이블이 즉시는 아님).

이 오류가 너무 간헐적이라는 사실 (2 주 만에 3 번 정도 발생했습니다-DB에 다른 부하가없고 응용 프로그램을 테스트하고 있음)은 저수준 문제를 너무 조심스럽게 만듭니다.


Django 는 기본 키를 지정하지 않으면 기본 키가 DBMS에 의해 생성 된다고 명시 합니다. 이제 @orokusaky가 파이썬 코드에서 무엇을하고 있는지 알지 못하지만 코드가 없다고 확신하기 때문에이 페이지에서 끝났습니다. 특정 기본 키를 사용하려고 시도했지만 DBMS가 잘못된 키를 사용하는 것을 보지 못했습니다.
mccc

답변:


34

PostgreSQL은 자체적으로 중복 값을 삽입하려고 시도하지 않으며 사용자는 자신 (응용 프로그램, ORM 포함)입니다.

PK 세트에 값을 잘못된 위치로 공급하는 시퀀스와 테이블에 이미 동일한 값이 포함되어 nextval()있거나 단순히 응용 프로그램이 잘못된 것을 수행하는 순서 일 수 있습니다. 첫 번째는 쉽게 고칠 수 있습니다.

SELECT setval('your_sequence_name', (SELECT max(id) FROM your_table));

두 번째는 디버깅을 의미합니다.

장고 (또는 다른 인기있는 프레임 워크)는 자체적으로 시퀀스를 재설정하지 않습니다. 그렇지 않으면 우리는 격일로 비슷한 질문을합니다.


다른 격리 수준에 대해 (여기서는 @andi의 답변을 바탕으로) 주목할 가치가 있습니까? 예를 들어, 첫 번째 쿼리가 완료되기 전에 두 번째 쿼리가 나오는 경우 트랜잭션을 사용하지 않는 시나리오에서 max(id)첫 번째 쿼리가 완료되기 전에 결과를 얻은 레코드를 삽입 할 수 있습니까? 같은 결과?
orokusaki

5

직렬 열 순서 값이 업데이트되지 않은 테이블에 행을 삽입하려고 할 가능성이 높습니다.

postgres에 대해 Django ORM에 의해 정의 된 기본 키인 테이블의 다음 열을 고려하십시오.

id serial NOT NULL

누구의 기본값이

nextval('table_name_id_seq'::regclass)

순서는 id 필드가 공백으로 설정된 경우에만 평가됩니다. 그러나 이미 테이블에 항목이 있으면 문제가됩니다.

질문은 왜 이전 항목이 시퀀스 업데이트를 트리거하지 않았습니까? 이전의 모든 항목에 대해 id 값이 명시 적으로 제공 되었기 때문입니다.

필자의 경우 초기 엔트리는 픽스쳐에서 마이그레이션을 통해로드되었습니다.

이 문제는 임의의 PK 값을 가진 사용자 지정 항목을 통해 까다로울 수 있습니다.

예를 들어 보자. 테이블에 10 개의 항목이 있습니다. PK = 15로 명시 적으로 입력합니다. 코드를 통한 다음 네 삽입은 완벽하게 작동하지만 다섯 번째 삽입은 예외를 발생시킵니다.

DETAIL: Key (id)=(15) already exists.

이 게시물에 감사드립니다. 나는 이와 같은 사례를 오랫동안 디버깅 해왔다. 거의 발생하지 않았습니다. 특정 "수동"관리 기능은 자체적으로 ID를 삽입하여 ID 카운터를 이전 값으로 남겨 둘 수 있음이 밝혀졌습니다. 이것은 "신분에 의해 생성됨"의 실제 위험입니다. 다음에 ID 열을 정의 할 때 "ALWAYS"대신 "BY DEFAULT"를 사용하기 전에 두 번 생각할 것입니다.
Michael

4

나는 거의 같은 오류로 여기에 왔으며 거의 ​​발생하지 않았으며 추적하기가 어려웠습니다.

서버에 POST를 두 번 수행하는 JS 반복 오류가 잘못되었습니다! 따라서 때로는 장고 (또는 다른 웹 프레임 워크)보기와 양식뿐만 아니라 매우 앞면에서 일어나는 일을 볼 가치가 있습니다.


1

그래 이상한 것. 필자의 경우 마이그레이션에서 데이터를로드하는 동안 잘못되었을 때 분명히 뭔가가 있습니다. 나는 빈 마이그레이션을 추가하고 초기 데이터, 내 경우에는 6 개의 레코드 를 추가하는 행을 작성했습니다 .

db_alias = schema_editor.connection.alias
bulk = []
for item in items:
    bulk.append(MyModel(
        id=item[0],
        value=item[1],
        slug=item[2],
        name=item[3],
    ))

MyModel.objects.using(db_alias).bulk_create(bulk)

그런 다음 관리자 패널에서 새 항목을 추가하려고 시도했지만 다음을 얻었습니다.

첫번째 시도:

DETAIL:  Key (id)=(1) already exists.

나중에 시도 :

DETAIL:  Key (id)=(2) already exists.
DETAIL:  Key (id)=(3) already exists.
DETAIL:  Key (id)=(4) already exists.
DETAIL:  Key (id)=(5) already exists.
DETAIL:  Key (id)=(6) already exists.

그리고 마지막으로 7 일과 시간이 모두 성공적입니다

그래서 6 개의 항목을로드 할 때 bulk_create와 관련된 것이있을 수 있습니다. Django 프로젝트에서 비슷한 원인 일 수 있습니다.

장고 1.9 PostgreSQL 9.3.14

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.