Birincil anahtar mı yoksa Benzersiz dizin mi?


127

İşyerinde birincil anahtarlar yerine benzersiz dizinlere sahip büyük bir veritabanımız var ve her şey yolunda gidiyor.

Yeni bir proje için yeni veritabanı tasarlıyorum ve bir ikilem yaşıyorum:

DB teorisinde, birincil anahtar temel unsurdur, sorun değil, ancak GERÇEK projelerde her ikisinin de avantajları ve dezavantajları nelerdir?

Projelerde ne kullanıyorsunuz?

DÜZENLEME: ... ve MS SQL sunucusundaki birincil anahtarlar ve çoğaltma ne olacak?


2
Burada tartışılan bazı ek hususlar vardır (bir kapsama dizininin ek bağlamıyla da olsa) - dba.stackexchange.com/questions/21554/…
StuartLC

NOT: SQLite, eski sorun nedeniyle ortak standarda karşı birincil anahtarın boş olmasına izin vermelerinden farklıdır. sqlite.org/lang_createtable.html
bitinn

Yanıtlar:


168

Benzersiz bir dizin nedir?

Bir sütundaki benzersiz bir dizin, o sütunda iki farklı satırda iki eşit değere sahip olamayacağınız sınırlamasını da uygulayan bir dizindir. Misal:

CREATE TABLE table1 (foo int, bar int);
EŞSİZ DİZİN OLUŞTUR ux_table1_foo tablo1 (foo); - foo'da benzersiz bir dizin oluşturun.

INSERT INTO table1 (foo, bar) VALUES (1, 2); -- TAMAM
INSERT INTO table1 (foo, bar) VALUES (2, 2); -- TAMAM
INSERT INTO table1 (foo, bar) VALUES (3, 1); -- TAMAM
INSERT INTO table1 (foo, bar) VALUES (1, 4); - Başarısız!

'Ux_table1_foo' anahtarı için yinelenen giriş '1'

Son ekleme başarısız olur, çünkü foo1 değerini bu sütuna ikinci kez eklemeye çalıştığında sütundaki benzersiz dizini ihlal eder .

MySQL'de benzersiz bir kısıtlama birden çok NULL'a izin verir.

Birden çok sütun üzerinde benzersiz bir dizin oluşturmak mümkündür.

Birincil anahtar ve benzersiz dizin

Aynı olan şeyler:

  • Birincil anahtar, benzersiz bir dizini ifade eder.

Farklı olan şeyler:

  • Bir birincil anahtar ayrıca NOT NULL anlamına gelir, ancak benzersiz bir dizin null yapılabilir.
  • Yalnızca bir birincil anahtar olabilir, ancak birden çok benzersiz dizin olabilir.
  • Tanımlanmış kümelenmiş dizin yoksa, birincil anahtar kümelenmiş dizin olacaktır.

4
Not, benzersiz bir dizin bir sütun üzerinde bir indeksi olan bir benzersiz bir dizin veya birincil anahtar birden fazla sütun içerir gibi tamamen doğru değildir.
Alex Jasmin

2
@Alexandre Jasmin: Düzeltildi. Birden çok sütunla ilgili kısım daha sonra bahsedilecektir.
Mark Byers

Boş değerlere referansla, ansi standartları, bir veri kümesinde, üzerinde benzersiz bir kısıtlamaya sahip birden çok boş değere izin verir ve bu, aynı zamanda Oracle ve PostgreSQL üzerindeki uygulamadır. Yine de SQL Server'ın yalnızca bir boş değere izin verdiğine inanıyorum.
David Aldridge

3
ancak yine de, birincil anahtarın ne zaman veya benzersiz dizin ne zaman kullanılacağı gibi, anlayamadım? veya her ikisi de aynı durumlarda olabilir.
Amit

33

Bunu şu şekilde görebilirsiniz:

Birincil Anahtar Benzersizdir

Benzersiz bir değerin Öğenin Temsili olması gerekmez

?; Anlamı Öğeyi tanımlamak için birincil anahtar kullanılır, eğer bir "Kişi" niz varsa, Kişiniz için Birincil olan bir Kişisel Kimlik Numarasına (SSN veya benzeri) sahip olmak istersiniz.

Öte yandan, kişinin benzersiz bir e-postası olabilir, ancak kişiyi tanımlamaz.

İlişki tablolarında (orta masa / bağlantı tablosu) bile her zaman Birincil Anahtarlara sahibim. Neden? Kod yazarken bir standardı takip etmeyi seviyorum, eğer "Kişi" nin bir tanımlayıcısı varsa, Arabanın bir tanımlayıcısı varsa, o zaman Kişi -> Otomobilin de bir tanımlayıcısı olmalıdır!


İlişki tablolarınızda: yapay bir birincil anahtar (örneğin bir tam sayı) içeren yeni bir sütun mu tanıttığınızı veya oluşturulmuş bir birincil anahtar (person_id, car_id) mi kullandığınızı mı söylüyorsunuz?

3
birincil anahtar (person_id, car_id) en iyisidir. Ama genellikle yeni bir sütun oluştururum, eminim biraz ek yük getirir, ancak bunun iyi olduğunu düşündüm. Daha sonraki bir senaryoda belirli bir ilişkiyle ilişki kurmak isteyip istemediğinizi asla bilemezsiniz.
Filip Ekberg

1
Yedek birincil anahtarın bileşik / birleştirme tablonuz için yaptığı diğer şey, manuel görevlerin bakımı kolay olmasıdır.
Robert C. Barth

2
Çocuğunuz olacaksa yalnızca birincil anahtara ihtiyacınız vardır. Değer hiçbir şey için kullanılmıyorsa, değer hiçbir yerde görünmüyorsa, neden bir sütun ve bir sıra ekleyelim? Access'in bir PK istemesini durdurmak için yapılıyor. Bir çocuktaki kaydı tanımlamanız gerekiyorsa bir PK yapın, aksi takdirde israf olur.

3
İlişkilerle ilgisi yoksa ne alakası var? Bir alanı gösteriyorsunuz ve bunun birincil olduğunu söylüyorsunuz. Ve? O zaman ne olur? Ve eğer doğal pk yoksa, bir sütun ve bir sıra ve bir tetikleyici ekliyorum ve hepsi ____? Bazılarının sadece Birincil olması gerekir. Kurallardan sebepsiz yere kaçınırım.

10

Yabancı anahtarlar, birincil anahtarların yanı sıra benzersiz kısıtlamalarla çalışır. Çevrimiçi Kitaplardan:

Bir FOREIGN KEY kısıtlamasının yalnızca başka bir tablodaki bir PRIMARY KEY kısıtlamasına bağlanması gerekmez; başka bir tablodaki UNIQUE kısıtlamasının sütunlarına başvurmak için de tanımlanabilir

İşlemsel çoğaltma için birincil anahtara ihtiyacınız vardır. Çevrimiçi Kitaplardan:

İşlem çoğaltma için yayınlanan tabloların birincil anahtarı olmalıdır. Bir tablo işlemsel çoğaltma yayınındaysa, birincil anahtar sütunlarıyla ilişkili herhangi bir dizini devre dışı bırakamazsınız. Bu dizinler çoğaltma için gereklidir. Bir dizini devre dışı bırakmak için, önce tabloyu yayından kaldırmanız gerekir.

Her iki yanıt da SQL Server 2005 içindir.


BU beni çok korkutuyor (ilk alıntı). Neden? PK'm olan keyfi bir kimliğe sahip bir kişi masam var ama Telefon, E-posta ve SSN'ye Birleşik Krallık eklemeye karar verdim ... yani şimdi 4 farklı tablo 4 farklı sütunda kişiye katılıyor mu? Tutarlılık için alabileceğiniz her türlü esnekliği unutacağımı düşünüyorum.

5

Doğal bir anahtar yerine vekil birincil anahtarın ne zaman kullanılacağının seçimi zordur. Her zaman ya da asla gibi yanıtlar nadiren yararlıdır. Duruma bağlı olduğunu görüyorum.

Örnek olarak, aşağıdaki tablolara sahibim:

CREATE TABLE toll_booths (
    id            INTEGER       NOT NULL PRIMARY KEY,
    name          VARCHAR(255)  NOT NULL,
    ...
    UNIQUE(name)
)

CREATE TABLE cars (
    vin           VARCHAR(17)   NOT NULL PRIMARY KEY,
    license_plate VARCHAR(10)   NOT NULL,
    ...
    UNIQUE(license_plate)
)

CREATE TABLE drive_through (
    id            INTEGER       NOT NULL PRIMARY KEY,
    toll_booth_id INTEGER       NOT NULL REFERENCES toll_booths(id),
    vin           VARCHAR(17)   NOT NULL REFERENCES cars(vin),
    at            TIMESTAMP     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    amount        NUMERIC(10,4) NOT NULL,
    ...
    UNIQUE(toll_booth_id, vin)
)

İki varlık tablomuz ( toll_boothsve cars) ve bir işlem tablomuz ( drive_through) var. toll_boothO değişim garanti edilmez hiçbir doğal niteliğini çünkü tablo bir vekil anahtar kullanır (isim kolaylıkla değiştirilebilir). carsOlmayan bir değiştirme bir kimliğe sahiptir çünkü tablo, doğal birincil anahtarı kullanır ( vin). drive_throughİşlem tablosu kolay tanımlama için bir vekil anahtar kullanır, aynı zamanda rekor takıldığında anda benzersiz olmasını garanti edildiği özelliklerde benzersiz bir kısıtlaması vardır.

http://database-programmer.blogspot.com'da bu özel konu hakkında bazı harika makaleler var.


4

Birincil anahtarların dezavantajları yoktur.

@MrWiggles ve @Peter Parker yanıtlarına sadece bazı bilgiler eklemek için, tablonun birincil anahtarı olmadığında, örneğin bazı uygulamalarda verileri düzenleyemezsiniz (örneğin, bunlar olmadan verileri düzenleyemez / silemez gibi) birincil anahtar). Postgresql, UNIQUE sütununda birden çok NULL değer olmasına izin verir, PRIMARY KEY, NULL'lara izin vermez. Ayrıca, kod üreten bazı ORM'lerin birincil anahtarları olmayan tablolarla ilgili bazı sorunları olabilir.

GÜNCELLEME:

Bildiğim kadarıyla tabloları MSSQL'de birincil anahtarlar olmadan çoğaltmak mümkün değil, en azından sorunsuz ( detaylar ) mümkün değil.


Yeni satırlar eklendiğinde veya bu sütun güncellendiğinde ek yük vardır.

3

Bir şey bir birincil anahtarsa, DB motorunuza bağlı olarak tüm tablo birincil anahtara göre sıralanır. Bu, aramaların birincil anahtarda çok daha hızlı olduğu anlamına gelir, çünkü başka herhangi bir tür dizinle ilgisi olduğu için herhangi bir başvuruyu geri çevirmek zorunda değildir. Bunun yanı sıra, bu sadece teori.


3
tablo, zorunlu olarak birincil anahtara göre değil, kümelenmiş dizine göre sıralanacaktır.
Ray Booysen

1
Çoğu kişi birincil anahtarını kümelenmiş dizin olarak ayarlar.
Ray Booysen

Tabi masalarımızdaki sıcak noktaları ve dengesiz indeks ağaçlarını sevmediğimiz sürece, bildiğimiz çoğu zaman Gerçekten Kötü bir Fikirdir ...
Mike Woodhouse

1
HER ZAMAN Gerçekten Kötü Bir Fikir Değildir. Verilerinizi bilin, RDBMS'nizi öğrenin, seçeneklerin ne anlama geldiğini bilin. Nadiren seçim HER ZAMAN iyi veya kötüdür. HER ZAMAN bir olsaydı, veritabanı onu zorunlu kılar veya izin vermezdi. Size seçenek veriyorlar çünkü 'Bağımlı'.

2

Diğer yanıtların söylediklerine ek olarak, bazı veritabanları ve sistemler bir birincilin mevcut olmasını gerektirebilir . Akla bir durum geliyor; Informix ile kurumsal çoğaltma kullanılırken, bir tablonun çoğaltmaya katılması için bir PK mevcut olmalıdır.


2

Bir değer için NULL'a izin vermediğiniz sürece, bunlar aynı şekilde ele alınmalıdır, ancak NULL değeri veritabanlarında farklı şekilde işlenir (AFAIK MS-SQL birden (1) NULL değerine izin vermez, mySQL ve Oracle buna izin verir bir sütun UNIQUE ise,) Yani gerekir bu sütunu dEĞİL BOŞ eŞSİZ INDEX tanımlamak


1
MS-SQL, her RDBMS'de olduğu gibi, benzersiz bir dizine sahip bir sütunda birden çok NULL değerine izin verir. Şöyle düşünün: NULL bir değer değildir, bu yüzden ikinci bir NULL eklediğinizde, asla mevcut olanla eşleşmeyecektir. İfade (NULL == NULL) doğru veya yanlış olarak değerlendirilmez, NULL olarak değerlendirilir.
gregmac

thanx gregmac, MS'in bunu takip edip etmediğinden emin değildim. Bununla birlikte bazı MS Quirks'i hatırladım, ancak birkaç yıl önce (2000 öncesi) ve eski bir erişim DB öksürüğü de olabilirdi
Peter Parker,

2

İlişkisel veri teorisinde birincil anahtar diye bir şey yoktur, bu nedenle sorunuzun pratik düzeyde yanıtlanması gerekir.

Benzersiz dizinler SQL standardının bir parçası değildir. Bir DBMS'nin özel uygulaması, benzersiz bir indeks bildirmenin sonuçlarının ne olduğunu belirleyecektir.

Oracle'da, bir birincil anahtar bildirmek, sizin adınıza benzersiz bir dizinin oluşturulmasıyla sonuçlanacaktır, bu nedenle soru neredeyse tartışmalıdır. Size diğer DBMS ürünlerinden bahsedemem.

Bir birincil anahtar bildirmeyi tercih ediyorum. Bu, anahtar sütun (lar) ındaki NULL’ları yasaklamanın yanı sıra kopyaları da yasaklamak gibi bir etkiye sahiptir. Ayrıca varlık bütünlüğünü güçlendirmek için REFERENCES kısıtlamalarını bildirmeyi de tercih ediyorum. Çoğu durumda, bir yabancı anahtarın coulmn (ları) üzerinde bir dizin bildirmek, birleşimleri hızlandıracaktır. Bu tür bir dizin genel olarak benzersiz olmamalıdır.


MS SQL Server'daki birincil anahtar her zaman hem EŞSİZ hem de BOŞ DEĞİLDİR - örneğin, gerçekten sadece Benzersiz bir dizindir, ancak ek kısıtlama ile NULL olamaz.
marc_s

Oracle, benzersiz olmayan bir indeksle Benzersiz Kısıtlama uygulayabilir. MSSS yapamazsa şaşırırdım. "Bu gerçekten sadece benzersiz bir endeks" demek kötü bir hizmettir.

"Çoğu durumda, bir yabancı anahtarın coulmn (ları) üzerinde bir dizin bildirmek, katılımları hızlandırır." Bu, eğer varsa hash birleşimlerinin tercih edildiği bir veri ambarlama dünyasında neredeyse her zaman doğru değildir.
JAC2703

OP depolardan bahsetmedi. Hash loins'in sql sunucusunda nasıl çalıştığından emin değilim. Depo güncelleme zamanında işin ne kadarı yapılabilir.
Walter Mitty

2

KÜMELENMİŞ ENDEKSLERİN EŞSİZ ENDEKSLERE karşı bazı dezavantajları vardır.

Daha önce de belirtildiği gibi, KÜMELENMİŞ ENDEKS, tablodaki verileri fiziksel olarak sıralar.

Bu, kümelenmiş bir dizin içeren bir tablo üzerinde çok fazla ekleme veya silme olduğunda, her seferinde (yani, neredeyse, doldurma faktörünüze bağlı olarak) verileri değiştirdiğinizde, fiziksel tablonun sıralı kalması için güncellenmesi gerektiği anlamına gelir.

Göreceli küçük tablolarda bu sorun değil, ancak GB değerinde veriye sahip tablolara ulaşıldığında ve eklemeler / silmeler sıralamayı etkiler, sorunlarla karşılaşacaksınız.


Avantajı ne o zaman? sıralı sorgular daha hızlı mı? Bu, verilerinizin çoğunu bir kez (veya nadiren) yazıp her zaman sorguladığınızda bir kullanım durumu için daha mı iyi?
Buffalo

1

Neredeyse hiçbir zaman sayısal birincil anahtarı olmayan bir tablo oluşturmam. Eşsiz olması gereken doğal bir anahtar varsa, ona da benzersiz bir dizin koyarım. Birleştirmeler, tamsayılarda çok sütunlu doğal anahtarlardan daha hızlıdır, verilerin yalnızca tek bir yerde değiştirilmesi gerekir (doğal anahtarların güncellenmesi gerekir, bu da birincil anahtarda - yabancı anahtar ilişkilerinde kötü bir şeydir). Çoğaltmaya ihtiyacınız olacaksa, tamsayı yerine bir GUID kullanın, ancak çoğunlukla, özellikle John Smith ve John Smith arasında ayrım yapmak için görmeleri gerekiyorsa, kullanıcı tarafından okunabilen bir anahtarı tercih ederim.

Vekil anahtar oluşturmadığım birkaç kez, çoktan çoğa bir ilişkiye dahil olan bir katılım masamın olduğu zamandır. Bu durumda, her iki alanı da birincil anahtar olarak ilan ediyorum.


"Neredeyse hiçbir zaman sayısal birincil anahtarı olmayan bir tablo oluşturmam": neden her zaman sayısal? Birincil anahtarın sayısal olması gerekmez (bu arada AUTO_INCREMENT olması da gerekmez).
Hibou57

@ Hinou57, çünkü doğal anahtarların nadiren gerçekten benzersiz ve neredeyse her zaman değiştirilebilir olduğunu buldum. Ayrıca, intergerlerdeki birleşimler genellikle varcahrr doğal anahtarları veya daha kötüsü bileşik anahtarlardaki birleştirmelerden çok daha hızlıdır. Onları çoğu zaman kullanmazdım. Bu, veritabanınızda sakladığınız bilgilerin türüne göre değişebilir, ancak kişisel deneyimlerime göre doğal anahtarların zaman içinde son derece güvenilmez olduğunu gördüm.
HLGEM

Cevap HLGEM için teşekkürler. Güvenilmez ile ne demek istiyorsun? Verim? (Umarım bu veri bütünlüğü anlamında bir güvenilirlik meselesi değildir). Tamsayı anahtarları veya kısa VARCHAR gibi daha doğal anahtarlar kullansam da, en basit DB motorlarında bile her yerde karma işlemi kullanıldığından, muhtemelen küçük bir fark yaratacağından, sözleriniz beni biraz şaşırttı.
Hibou57

Çoğu durumda güvenilmezdir çünkü olmaları gerekse bile güvenilir bir şekilde benzersiz değildirler. Güvenilmezler çünkü değişiyorlar ve bu bir uopdate'deki milyonlarca kaydı etkileyebilir. Bu, birçok farklı bilgi türü hakkında veri depolayan yüzlerce veritabanından verileri görme ve yönetme veya sorgulama deneyimimdir.
HLGEM

1

Anladığım kadarıyla, bir birincil anahtar ve boş olmayan bir kısıtı olan benzersiz bir dizin aynıdır (*); ve spesifikasyonun açıkça neyi ifade ettiğine veya ima ettiğine bağlı olarak birini veya diğerini seçtiğini varsayıyorum (ne ifade etmek ve açıkça uygulamak istediğinize bağlı olarak). Benzersizlik gerektiriyorsa ve boş değilse, onu birincil anahtar yapın. Böyle bir durum meydana gelirse, benzersiz bir dizinin tüm bölümleri, buna gereksinim olmaksızın boş olmazsa, o zaman onu benzersiz bir dizin yapın.

Geriye kalan tek fark, birden fazla boş olmayan benzersiz dizine sahip olmanıza karşın, birden çok birincil anahtarınız olamaz.

(*) Pratik bir fark dışında: Bir birincil anahtar, yabancı anahtar tanımlama gibi bazı işlemler için varsayılan benzersiz anahtar olabilir. Ör. biri bir tabloya başvuran bir yabancı anahtar tanımlar ve sütun adını sağlamazsa, başvurulan tablonun birincil anahtarı varsa, birincil anahtar başvurulan sütun olur. Aksi takdirde, başvurulan sütunun açıkça adlandırılması gerekecektir.

Buradaki diğerleri DB replikasyonundan bahsetti, ancak bunu bilmiyorum.


0

Benzersiz Dizin bir NULL değerine sahip olabilir. KÜMELENMEYEN ENDEKS oluşturur. Birincil Anahtar NULL değer içeremez. CLUSTERED INDEX oluşturur.


0

MSSQL'de, kümelenmiş dizinde en iyi performans için Birincil anahtarlar monoton olarak artmalıdır. Bu nedenle, kimlik ekli bir tam sayı, monoton olarak artmayan herhangi bir doğal anahtardan daha iyidir.


-1

Bana kalırsa...

Veritabanının ve uygulamalarınızın gereksinimlerini karşılamanız gerekir.

Her tabloya otomatik olarak artan bir tam sayı veya uzun id sütunu ekleyerek birincil anahtar olarak hizmet vermek veritabanı gereksinimlerini karşılar.

Daha sonra, uygulamanızın kullanması için tabloya en az bir benzersiz dizin daha eklersiniz. Bu çalışan_kimliği, hesap_kimliği veya müşteri_kimliği vb. Üzerindeki dizin olabilir. Mümkünse, bu dizin bileşik bir dizin olmamalıdır.

Çeşitli alanlardaki endeksleri tek tek bileşik endekslere tercih ederim. Veritabanı, where cümlesi bu alanları içerdiğinde tek alan indekslerini kullanır, ancak alanları tam olarak doğru sırada sağladığınızda yalnızca bir bileşik kullanır - yani, siz sağlamadığınız sürece bir bileşik dizindeki ikinci alanı kullanamaz. where cümlenizdeki hem birinci hem de ikinci.

Ben tamamen hesaplanmış veya Fonksiyon tipi indeksleri kullanmaktan yanayım ve bunların bileşik indeksler yerine kullanılmasını tavsiye ederim. Where cümlenizde aynı işlevi kullanarak işlev indeksini kullanmayı çok kolaylaştırır.

Bu, başvuru gereksinimlerinizi karşılar.

Diğer birincil olmayan endekslerin aslında anahtar değerini rowid () 'ler ile değil, bir birincil anahtar değerine dizinler. Bu, fiziksel sıralama işlemlerinin ve silmelerin bu indeksleri yeniden oluşturmak zorunda kalmadan gerçekleşmesine izin verir.

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.