Tại sao Postgres tạo ra một giá trị PK đã được sử dụng?


19

Tôi đang sử dụng Django và thỉnh thoảng tôi gặp lỗi này:

IntegrityError: giá trị khóa trùng lặp vi phạm ràng buộc duy nhất "myapp_mymodel_pkey"
CHI TIẾT: Khóa (id) = (1) đã tồn tại.

Cơ sở dữ liệu Postgres của tôi trên thực tế có một đối tượng myapp_mymodel với khóa chính là 1.

Tại sao Postgres lại cố gắng sử dụng khóa chính đó? Hoặc, đây có phải là ứng dụng của tôi (hoặc ORM của Django) gây ra điều này không?

Vấn đề này xảy ra thêm 3 lần liên tiếp. Những gì tôi đã tìm thấy là khi nó không xảy ra nó sẽ xảy ra một hoặc nhiều lần liên tiếp cho một bảng nhất định, sau đó không một lần nữa. Nó dường như xảy ra cho mọi bảng trước khi nó dừng hoàn toàn trong nhiều ngày, xảy ra ít nhất một phút hoặc lâu hơn cho mỗi bảng khi nó xảy ra và chỉ xảy ra không liên tục (không phải tất cả các bảng ngay lập tức).

Thực tế là lỗi này không liên tục (chỉ xảy ra 3 lần hoặc hơn trong 2 tuần - không có tải nào khác trên DB, chỉ cần tôi kiểm tra ứng dụng của mình) là điều khiến tôi cảnh giác với vấn đề cấp thấp.


Django đặc biệt tuyên bố rằng khóa chính được tạo bởi DBMS trừ khi được chỉ định - bây giờ, tôi không biết @orokusaky đang làm gì trong mã python của mình, nhưng tôi đã kết thúc trên trang này vì tôi khá tự tin rằng tôi không có mã đang cố gắng sử dụng một khóa chính cụ thể và tôi chưa bao giờ thấy một DBMS đang cố sử dụng một khóa sai.
mccc

Câu trả lời:


33

PostgreSQL sẽ không cố gắng tự chèn các giá trị trùng lặp, chính bạn (bao gồm cả ứng dụng của bạn, bao gồm ORM).

Nó có thể là một chuỗi cung cấp các giá trị cho PK được đặt sai vị trí và bảng đã chứa giá trị bằng với nó nextval()- hoặc đơn giản là ứng dụng của bạn làm sai. Cách đầu tiên rất dễ sửa:

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

Cái thứ hai có nghĩa là gỡ lỗi.

Django (hoặc bất kỳ khung phổ biến nào khác) không tự thiết lập lại trình tự - nếu không chúng tôi sẽ có câu hỏi tương tự mỗi ngày.


Có đáng chú ý không (cũng dựa trên câu trả lời của @ andi's ở đây) về các mức độ cô lập khác nhau? Chẳng hạn, nếu truy vấn thứ hai xuất hiện trước khi hoàn thành truy vấn đầu tiên, thì có thể đưa ra một kịch bản khi tôi không sử dụng giao dịch, chèn một bản ghi dẫn đến việc nhận được max(id)trước khi truy vấn đầu tiên hoàn thành, và sau đó dẫn đến cả hai kết quả tương tự?
orokusaki

5

Bạn rất có thể buộc phải chèn một hàng vào bảng mà giá trị chuỗi cột nối tiếp không được cập nhật.

Xem xét cột sau trong bảng của bạn, đó là khóa chính được xác định bởi Django ORM cho postgres

id serial NOT NULL

Giá trị mặc định của ai được đặt thành

nextval('table_name_id_seq'::regclass)

Trình tự chỉ được đánh giá khi trường id được đặt thành trống. Nhưng đó là vấn đề nếu đã có mục vào bảng.

Câu hỏi là tại sao những mục trước đó không kích hoạt trình tự cập nhật? Đó là bởi vì giá trị id được cung cấp rõ ràng cho tất cả các mục trước đó.

Trong trường hợp của tôi, những mục nhập ban đầu được tải từ đồ đạc thông qua việc di chuyển.

Vấn đề này cũng có thể gặp khó khăn thông qua các mục tùy chỉnh với giá trị PK ngẫu nhiên.

Nói ví dụ. Có 10 mục vào bảng của bạn. Bạn thực hiện một mục rõ ràng với PK = 15. Bốn lần chèn tiếp theo thông qua mã sẽ hoạt động hoàn toàn tốt nhưng lần thứ 5 sẽ đưa ra một ngoại lệ.

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

Cám ơn vì bài viết. Tôi đã gỡ lỗi một trường hợp như thế này trong một thời gian dài. Rất hiếm khi nó xảy ra. Hóa ra, một chức năng quản trị "thủ công" cụ thể có thể tự chèn id, để lại bộ đếm nhận dạng với một giá trị cũ. Đây là một mối nguy hiểm thực sự với "ĐƯỢC TẠO B DENG DEFAULT NHƯ IDENTITY". Tôi sẽ suy nghĩ kỹ trước khi sử dụng "BY DEFAULT" thay vì "LUÔN" trong lần tiếp theo tôi xác định một cột định danh.
Michael

4

Tôi đã kết thúc ở đây với lỗi rất giống nhau, điều này hiếm khi xảy ra, và rất khó để theo dõi, bởi vì tôi đang tìm kiếm nó không phải là nơi tôi nên.

Lỗi là sự lặp lại của JS đã thực hiện POST cho máy chủ hai lần! Vì vậy, đôi khi rất đáng để có một cái nhìn không chỉ về các hình thức và hình thức django (hoặc bất kỳ khung web nào khác) mà còn cả những gì xảy ra ở phía trước.


1

Vâng, điều kỳ lạ. Trong trường hợp của tôi, một cái gì đó rõ ràng khi sai trong khi tải dữ liệu di chuyển. Tôi đã thêm di chuyển trống và viết các dòng để thêm một số dữ liệu ban đầu, 6 bản ghi trong trường hợp của tôi.

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)

Sau đó, trong bảng quản trị, tôi đã cố gắng thêm mục mới và nhận:

Nỗ lực đầu tiên:

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

Những lần thử sau:

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.

Và cuối cùng thứ 7 và lần nào cũng thành công

Vì vậy, tôi đang nói có thể có một cái gì đó liên quan đến Bulk_create khi tôi tải 6 mục ở đó. Nó có thể là một cái gì đó tương tự trong dự án Django của bạn gây ra điều đó.

Django 1.9 PostgreQuery 9.3,14

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.