Postgres neden zaten kullanılmış bir PK değeri üretiyor?


22

Django kullanıyorum ve arada bir bu hatayı alıyorum:

IntegrityError: yinelenen anahtar değeri "myapp_mymodel_pkey" benzersiz sınırlamasını ihlal ediyor
DETAIL: Key (id) = (1) zaten var.

Postgres veritabanımın aslında birincil anahtar 1 olan bir myapp_mymodel nesnesi var.

Postgres neden bu birincil anahtarı tekrar kullanmaya çalışsın? Ya da bu büyük olasılıkla uygulamamın (ya da Django'nun ORM) buna neden olması mı?

Bu sorun şu anda üst üste 3 kez daha oluştu. Bulduğum şey , gerçekleştiğinde, verilen bir tablo için arka arkaya bir veya daha fazla kez gerçekleşir, sonra tekrar olmaz. Her tablo için günlerce tamamen durmadan önce, gerçekleştiğinde tablo başına en az bir dakika kadar ve sadece aralıklı olarak gerçekleşiyor gibi görünüyor (tüm tablolar hemen değil).

Bu hatanın çok aralıklı olması (2 haftada sadece 3 ya da daha fazla kez oldu - DB'de başka bir yük yok, sadece uygulamanızı test ediyorum) beni düşük seviyeli bir soruna karşı bu kadar ihtiyatlı kılan şey.


Django özellikle belirtmedikçe birincil anahtar DBMS tarafından oluşturulduğunu belirtir - şimdi, @orokusaky'nin python kodunda ne yaptığını bilmiyorum, ancak kodun olmadığından oldukça emin olduğum için bu sayfada son buldum belirli bir birincil anahtar kullanmaya çalışıyorum ve hiç yanlış bir anahtar kullanmaya çalışan bir DBMS görmedim.
mccc

Yanıtlar:


34

PostgreSQL yinelenen değerleri kendi başına eklemeye çalışmaz, siz (uygulamanız, ORM dahil) sizsiniz.

Değerleri PK'ye yanlış konuma ayarlanmış olarak besleyen bir sekans olabilir ve değeri zaten buna eşit olan tablo nextval()- ya da basitçe uygulamanız yanlış şeyi yapar. İlki düzeltmek kolaydır:

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

İkincisi, hata ayıklama anlamına gelir.

Django (veya başka herhangi bir popüler çerçeve) dizileri kendi başına sıfırlamaz - aksi takdirde her gün benzer sorular olurdu.


Farklı izolasyon seviyeleri hakkında (burada @ andi'nin cevabına da dayanarak) kayda değer mi? Örneğin, ikinci sorgu ilk tamamlanmadan önce gelirse, işlemleri kullanmadığım bir senaryo verildiğinde max(id), ilk sorgu tamamlanmadan önce elde edilen ve ardından her ikisinin de aynı sonuç?
orokusaki

7

Büyük olasılıkla, seri sütun sırası değerinin güncellenmediği bir tabloya satır eklemeye bağlıyorsunuz.

Tablonuzda postgres için Django ORM tarafından tanımlanan birincil anahtar olan aşağıdaki sütunu düşünün

id serial NOT NULL

Varsayılan değeri olarak ayarlanan

nextval('table_name_id_seq'::regclass)

Sekans yalnızca kimlik alanı boş olarak ayarlandığında değerlendirilir. Ancak, zaten tabloya girdiler varsa bu sorun olur.

Soru, bu önceki girişlerin neden dizi güncellemesini tetiklemediğidir? Bunun nedeni, id değerinin önceki tüm girişler için açıkça sağlanmış olmasıdır.

Benim durumumda, bu ilk girişler demirbaşlardan göçler yoluyla yüklendi.

Bu sorun, rastgele PK değerine sahip özel girişler yoluyla da zor olabilir.

Örneğin deyin. Masanıza 10 giriş var. PK = 15 ile açık bir giriş yaparsınız. Sonraki dört ek kodla mükemmel bir şekilde çalışacak, ancak 5. eklenti bir istisna oluşturacaktır.

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

Bu gönderi için teşekkürler. Uzun zamandır böyle bir davada hata ayıklama yapıyorum. Çok nadiren meydana geldi. Belirli bir "manuel" yönetici işlevinin kendi başına kimlik ekleyebileceği ve kimlik sayacını eski bir değerle bıraktığı ortaya çıktı. "KİMLİK VARSAYILAN TARAFINDAN ÜRETİLEN" bu gerçek bir tehlikedir. Bir dahaki sefere bir kimlik sütunu tanımlamak kez "HER ZAMAN" yerine "VARSAYILAN" kullanmadan önce iki kez düşüneceğim.
Michael

4

Burada nadiren meydana gelen ve izlenmesi zor olan çok aynı hatayla sonuçlandım, çünkü nerede olmam gerektiğini aradım.

Hata sunucuya iki kez POST yapan JS tekrarı oldu! Bu yüzden bazen sadece django (veya başka bir web çerçevesi) görünüm ve formlarınıza değil, aynı zamanda çok ön tarafta neler olduğuna da bakmaya değer.


1

Evet garip bir şey. Benim durumumda, taşıma işlemlerinde veri yüklenirken yanlış olduğunda bir şey göründü. Boş geçiş ekledim ve ilk veriyi eklemek için satırları yazdım, benim durumumda 6 kayıt .

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)

Sonra yönetici panelinde yeni öğe eklemeye çalıştım ve şunları aldım:

İlk girişim:

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

Daha sonraki denemeler:

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.

Ve son olarak 7. ve zamanında hepsi başarılı

Yani ben orada 6 öğe yüklediğiniz gibi bulk_create ile ilgili bir şey olduğunu söylüyorum. Belki de buna neden olan Django projenizde benzer bir şey olabilir.

Django 1.9 PostgreSQL 9.3.14

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.