bileşik birincil anahtarlar kötü bir uygulamadır? [kapalı]


16

Bileşik birincil anahtarların kötü bir uygulama olup olmadığını ve eğer değilse, hangi senaryoların kullanılması tavsiye edildiğini bilmek istiyorum.

Sorum bu makaleye dayanıyor

veritabanları tasarım hataları

Bileşik birincil anahtarlarla ilgili bölüm:

Kötü Uygulama No. 6: Kompozit Birincil Anahtarlar

Günümüzde birçok veritabanı tasarımcısı, iki veya daha fazla alanın birleşimi ile tanımlanan bileşik bir anahtar yerine, bir tamsayı ID otomatik olarak oluşturulan alanı birincil anahtar olarak kullanma hakkında konuştuğundan, bu bir tür tartışmalı bir noktadır. Bu şu anda “en iyi uygulama” olarak tanımlanıyor ve ben şahsen buna katılma eğilimindeyim.

Bileşik birincil anahtarın görüntüsü

Bununla birlikte, bu sadece bir sözleşmedir ve elbette, DBE'ler birçok tasarımcının kaçınılmaz olduğunu düşündüğü bileşik birincil anahtarların tanımına izin verir. Bu nedenle, artıklıkta olduğu gibi, bileşik birincil anahtarlar bir tasarım kararıdır.

Bununla birlikte, bileşik birincil anahtar içeren tablonuzun milyonlarca satır olması bekleniyorsa, bileşik anahtarı denetleyen dizin, CRUD işlem performansının çok düşük olduğu bir noktaya kadar büyüyebilir. Bu durumda, dizini yeterince kompakt olacak basit bir tamsayı kimliği birincil anahtarı kullanmak ve benzersizliği korumak için gerekli DBE kısıtlamalarını oluşturmak çok daha iyidir.


4
Bu "iyi" veya "kötü" bir uygulama değildir. Her tasarım kararı bir amaca hizmet etmelidir; (kendinize ve başkalarına) neden bileşik bir PK'ya ihtiyacınız olduğunu açıklayabilirseniz, gitmekte fayda var. Tersine, neden ihtiyacınız olmadığını açıklayabilirseniz, gitmek de iyidir. Bağlantı verdiğiniz makale bence çok kötü bir iş açıklıyor.
mustaccio

Bu makale bir noktaya işaret ediyor, ancak "en iyi uygulamaları" nda popüler çerçevelere (örneğin raylar gibi) bakarsak, bu tür birincil anahtarları desteklemiyorsa, neden sordum? teknik zorluklar ya da başka bir şey için.
hackvan

Çerçeve tasarımlarının sadece "basit" tek sütun tam sayı birincil anahtarlarını desteklemesi daha kolaydır. Çoğu geliştirici (en azından kişisel deneyimime göre) veritabanı becerileri açısından (en azından bu sitenin kullanıcılarına göre) fazla olmadığından, yazılımın çoğu kullanıcısı için yeterince iyi çalışır. Yazılımın çoğu kullanıcısı kompozit anahtarlara ihtiyaç duymadığından (veya en azından başlangıçta ihtiyaç duyduklarını düşünmediğinden), kompozit anahtarlar için (iyi) destek sağlamadan kurtulabilirler.
Willem Renzema

1
GUID nasıl INTEGER'dan daha iyidir [Seri | Otomatik_Katma | Kimlik | <whatever_integer_you_like>]?
Vérace

4
Bu yazarı işe
paparazzo

Yanıtlar:


32

Kullanımının "Composite keys as PRIMARY KEY is bad practice"tamamen saçmalık olduğunu söylemek !

Kompozit PRIMARY KEYs genellikle çok "iyi bir şey" dir ve günlük yaşamda meydana gelen doğal durumları modellemenin tek yoludur!

Öğrencilerin ve derslerin klasik Veritabanları-101 öğretim örneğini ve birçok öğrenci tarafından alınan birçok dersi düşünün!

Tablo kursu ve öğrenci oluşturun:

CREATE TABLE course
(
  course_id SERIAL,
  course_year SMALLINT NOT NULL,
  course_name VARCHAR (100) NOT NULL,
  CONSTRAINT course_pk PRIMARY KEY (course_id)
);


CREATE TABLE student
(
  student_id SERIAL,
  student_name VARCHAR (50),
  CONSTRAINT student_pk PRIMARY KEY (student_id)
);

Size PostgreSQL lehçesinde (ve MySQL ) örnek vereceğim - biraz tweaking ile herhangi bir sunucu için çalışmalıdır.

Şimdi, belli ki öğrenci hangi ders alıyor aldığını izlemek istiyoruz - Bir denen zorunda joining table(diğer adıyla linking, many-to-manyveya m-to-ntablolar). Ayrıca associative entitiesdaha teknik jargonda da bilinirler !

1 dersin birçok öğrencisi olabilir.
1 öğrenci birçok ders alabilir .

Böylece, bir birleştirme tablosu oluşturursunuz

CREATE TABLE course_student
(
  cs_course_id INTEGER NOT NULL,
  cs_student_id INTEGER NOT NULL,

  -- now for FK constraints - have to ensure that the student
  -- actually exists, ditto for the course.

  CREATE CONSTRAINT cs_course_fk FOREIGN KEY (cs_course_id) REFERENCES course (course_id),
  CREATE CONSTRAINT cs_student_fk FOREIGN KEY (cs_student_id) REFERENCES student (student_id)
);

Şimdi, bu tabloya anlamlı bir şekilde a vermenin tek yolu PRIMARY KEY, bunu KEYelbette ve öğrencinin bir kombinasyonu haline getirmektir . Bu şekilde elde edemezsiniz:

  • bir öğrenci ve ders kombinasyonu kopyası

    • bir kursa aynı öğrencinin yalnızca bir kez kayıt yaptırması ve

    • bir öğrenci aynı derse yalnızca bir kez kayıt yaptırabilir

  • Ayrıca, KEYöğrenci başına kurs için hazır bir arama yapıyorsunuz - AKA kapsayan bir endeks ,

  • hiç ders almayan öğrenciler ve öğrenciler olmadan ders bulmak önemsizdir!

    - db-fiddle örneğinin PK kısıtlaması OLUŞTUR TABLOSUNA katlanmış olması - Her iki şekilde de yapılabilir. CREATE TABLE ifadesinde her şeyin olmasını tercih ederim.


ALTER TABLE course_student 
ADD CONSTRAINT course_student_pk 
PRIMARY KEY (cs_course_id, cs_student_id);

Şimdi, öğrenci tarafından UNIQUE INDEXyapılan aramanın yavaş olduğunu tespit ediyorsanız, on (sc_student_id, sc_course_id) kullanabilirsiniz.

ALTER TABLE course_student 
ADD CONSTRAINT course_student_sc_uq  
UNIQUE (cs_student_id, cs_course_id);

Orada hiçbir onlar - dizinleri eklemek için gümüş kurşun edecek hale INSERTs ve UPDATEyavaş s, ama derece büyük yararı de azalanSELECT kez! Bu onların bilgi ve deneyim verilen endekse karar vermek ancak kompozit söylemek geliştirici kalmış PRIMARY KEYler vardır hep sadece düz yanlış kötü.

Tablolara katılma durumunda, genellikle mantıklı olan tek PRIMARY KEY şeydir! Tablolara katılmak, iş veya doğa ya da düşünebildiğim hemen hemen her alanda olanları modellemenin tek yoludur.

Bu PK aynı zamanda covering indexaramaların hızlanmasına yardımcı olabilecek bir kullanım alanıdır . Bu durumda, bir kişinin düzenli olarak (course_id, student_id) arama yapması özellikle yararlı olabilir, ki bu çoğu zaman böyle olabilir!

Bu, bir kompozitin PRIMARY KEYçok iyi bir fikir olabileceği küçük bir örnektir ve gerçekliği modellemenin tek akılcı yolu! Başımın üstünden, çok daha fazlasını düşünebilirim .

Kendi işimden bir örnek!

Bir flight_id, kalkış ve varış havalimanları listesi ve ilgili saatleri içeren bir uçuş masasını ve mürettebat üyeleriyle birlikte bir cabin_crew masasını düşünün!

Bunun modellenebilmesinin tek aklı yolu, flight_id ve crew_id ile att_ olarak bir flight_crew masaya sahip olmak ve tek aklı başında PRIMARY KEYiki alanın bileşik anahtarını kullanmaktır!


2
kurs ve öğrenciler örneğinde, course_student'ın idbirincil anahtar ve benzersiz bir dizin üzerinde cs_student_id cs_course_idolması ve aynı sonuçları alması mümkün mü ?
Hackvan

2
Bunu neden kaynak israf ediyor? PK (course_id, student_id) ile tanım gereği zaten bu alanlarda benzersiz bir dizin var! Aramaları hızlandırmak için benzersiz bir dizin (student_id, course_id) yararlı olabilir - herhangi bir ders almayan, ancak bu karar işlevsel olabilir, ancak bu günlerde nispeten ucuz depolama, Özellikle tablonun çok sık güncellenmeyeceğini düşünürdüğüm için tavsiye ederim.
Vérace

1
Bağlantı tabloları için tamamen katılıyorum - şu anda birkaçıyla çalışıyorum. Ancak, C # şapkamı taktığımda, reversepoco jeneratörü ile çalışıyorum ve bir sonraki katman için yararlı sınıflar (bul, kaydet vb) oluşturuyorum. Büyük bir soruna çarptım - kompozit anahtarlar herhangi bir genel kaydetme / bulma koduna sahip olmak için bir PITA olur. Evet, belki EDMX dosyalarına geri dönebilirim ama yine de özel durum kodu (Pkey sütunları say)? kompozitler gibi olmayan insanlar App katman kodundan konuşuyor
Richard Griffiths

Uçların sıklığına ve indeks birleştirme sıklığının bakım penceresine kıyasla bu daha iyi bir çözümdür. Ancak bazı tasarım seçenekleri, hemen görünmeyen gereksinimlerden kaynaklanan tavizlerdir. Ancak bir yorumun söylediği gibi, her iki senaryonun artılarını / eksilerini tanımlayın ve bir tasarım seçimi yapın.
Jonathan Fite

Bir öğrenci dersi tekrarladığında ne olur? Zamanla ayrılmış dersler farklı kimlikler almadığı sürece, başka bir eşleme tablonuz var. Veya kurs tarihi için şimdi anahtara eklenmesi gereken bir alan ekleyin.
iheanyi

3

Yarı eğitimli yaklaşımım: "birincil anahtar", tablodaki verileri aramak için kullanılan tek benzersiz anahtar olmak zorunda değildir, ancak veri yönetimi araçları varsayılan seçim olarak sunar. Bu nedenle, tablo sütunu olarak iki sütundan oluşan bir kompozit veya rastgele (muhtemelen seri) üretilen bir sayıya sahip olup olmadığınızı seçmek için, aynı anda iki farklı anahtarınız olabilir.

Veri değerleri satırı temsil edebilecek uygun bir benzersiz terim içeriyorsa, bunu "sentetik" anahtar kullanmak yerine "birincil anahtar" olarak tanımlamayı tercih ederim. Sentetik anahtar teknik nedenlerle daha iyi performans gösterebilir, ancak kendi varsayılan seçimim, hizmetinizi çalıştırabilmeniz için gerçekten başka bir yola gitmeniz gerekmedikçe, gerçek terimi birincil anahtar olarak atamak ve kullanmaktır.

Microsoft SQL Server, verilerin fiziksel olarak depolanmasını dizin sırasına göre kontrol eden ve diğer dizinlerin içinde kullanılan "kümelenmiş dizin" in farklı ancak ilgili özelliğine sahiptir. Varsayılan olarak, kümelenmiş dizin olarak birincil anahtar oluşturulur, ancak tercihen kümelenmiş dizini oluşturduktan sonra bunun yerine kümelenmemiş olanı seçebilirsiniz. Böylece kümelenmiş dizin olarak bir tamsayı kimlik oluşturulmuş sütuna ve birincil anahtar olarak nvarchar dosya adına (128 karakter) sahip olabilirsiniz. Dosya adını diğer tablolarda yabancı anahtar terimi olarak saklasanız bile, kümelenmiş dizin anahtarı dar olduğu için bu daha iyi olabilir - ancak bu örnek bunu yapmamak için iyi bir durumdur.

Tasarımınız, ilgili verileri tanımlamak için elverişsiz bir birincil anahtar içeren veri tablolarını içe aktarmayı içeriyorsa, bununla oldukça fazla sıkışmışsınız demektir.

https://www.techopedia.com/definition/5547/primary-key , müşterinin sosyal güvenlik numarası olan verileri tüm veri tablolarında müşteri anahtarı olarak depolayıp depolamayacağınızı veya kaydettirin. Aslında bu, çalışıp çalışmadığının yanı sıra SSN'nin ciddi bir istismarıdır; kişisel ve gizli bir veri değeridir.

Bu nedenle, anahtar olarak gerçek dünyadaki bir olguyu kullanmanın avantajı, "Müşteri" tablosuna katılmadan, diğer tablolarda onlar hakkında bilgi alabilmenizdir - ancak bu aynı zamanda bir veri güvenliği sorunudur.

Ayrıca, SSN veya başka bir veri anahtarı yanlış kaydedildiyse sorun yaşarsınız, bu nedenle yalnızca "Müşteri" yerine 20 kısıtlamalı tabloda yanlış değere sahipsiniz. Sentetik customer_id'in harici bir anlamı olmadığı için yanlış bir değer olamaz.


1
Özellikle müşteri verilerine anahtar olarak bağlı olarak, hatta bilinen benzersiz müşteri verileri (burada SSN) bile, bu verilerin düzeltilmesi gerektiğinde bozulduğu gözlemini takdir ediyorum.
ToolmakerSteve
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.