Her zaman birincil anahtar olarak tek bir tamsayı sütununun dezavantajı ne olabilir?


18

Üzerinde çalıştığım bir Web uygulaması içinde, tüm veritabanı işlemleri Entity Framework ORM üzerinde tanımlanan bazı genel depolar kullanılarak soyutlanır.

Ancak, genel havuzlar için basit bir tasarıma sahip olmak için, ilgili tüm tablolar benzersiz bir tamsayı tanımlamalıdır ( Int32C #, intSQL'de). Şimdiye kadar, bu her zaman masanın PK'sı ve aynı zamanda IDENTITY.

Yabancı anahtarlar yoğun olarak kullanılır ve bu tamsayı sütunlarına başvururlar. Hem tutarlılık hem de ORM tarafından navigasyon özellikleri oluşturmak için gereklidirler.

Uygulama katmanı genellikle aşağıdaki işlemleri gerçekleştirir:

  • tablodan ilk veri yüklemesi (*) -SELECT * FROM table
  • Güncelleme -UPDATE table SET Col1 = Val1 WHERE Id = IdVal
  • Sil -DELETE FROM table WHERE Id = IdVal
  • Ekle -INSERT INTO table (cols) VALUES (...)

Daha az sıklıkta yapılan işlemler:

  • TopluBULK INSERT ... into table veri - ardından (*) tüm veri yükü (oluşturulan tanımlayıcıları almak için)
  • Toplu silme - bu normal bir silme işlemidir, ancak ORM açısından "hantal":DELETE FROM table where OtherThanIdCol = SomeValue
  • Toplu güncelleme - bu normal bir güncelleme işlemidir, ancak ORM açısından "hantal":UPDATE table SET SomeCol = SomeVal WHERE OtherThanIdCol = OtherValue

* tüm küçük tablolar uygulama düzeyinde önbelleğe alınır ve neredeyse hepsi SELECTsveritabanına ulaşmaz. Tipik bir desen ilk yük ve çok sayıda INSERTs, UPDATEs ve DELETEs'dir.

Mevcut uygulama kullanımına bağlı olarak, tabloların herhangi birinde 100M kayıtlarına ulaşma şansı çok düşüktür.

Soru: Bir DBA'nın bakış açısından, bu tablo tasarım sınırlamasına sahip olarak karşılaşabileceğim önemli sorunlar var mı?

[DÜZENLE]

Yanıtları okuduktan sonra (harika geri bildirim için teşekkürler) ve başvurulan makaleleri, daha fazla ayrıntı eklemem gerektiğini hissediyorum:

  1. Mevcut uygulama özellikleri - Mevcut web uygulaması hakkında bahsetmedim, çünkü modelin diğer uygulamalar için de tekrar kullanılıp kullanılamayacağını anlamak istiyorum. Ancak benim özel durumum, bir DWH'den çok sayıda meta veri ayıklayan bir uygulamadır. Kaynak veriler oldukça dağınık (tuhaf bir şekilde denormalize, bazı tutarsızlıklar, birçok durumda doğal tanımlayıcı vb. Yok) ve uygulamam net ayrılmış varlıklar oluşturuyor. Ayrıca, oluşturulan tanımlayıcıların ( IDENTITY) çoğu görüntülenir, böylece kullanıcı bunları iş anahtarları olarak kullanabilir. Bu, büyük bir kod yeniden düzenlemesinin yanı sıra GUID'lerin kullanımını hariç tutar .

  2. "Bir sırayı benzersiz bir şekilde tanımlamanın tek yolu olmamalı" (Aaron Bertrand ♦) - bu çok iyi bir tavsiye. Tüm tablolarımda, işletme kopyalarına izin verilmemesini sağlamak için BENZERSİZ BİR KISIT tanımlanır.

  3. Ön uç uygulama odaklı tasarım ve veritabanı odaklı tasarım - tasarım seçimi bu faktörlerden kaynaklanır

    1. Varlık Çerçevesi sınırlamaları - birden çok sütun PK'ya izin verilir, ancak değerleri güncellenemez

    2. Özel sınırlamalar - tek bir tamsayı anahtarına sahip olmak, veri yapılarını ve SQL dışı kodu büyük ölçüde basitleştirir. Örn: tüm değer listelerinin bir tamsayı tuşu ve görüntülenen değerleri vardır. Daha da önemlisi, önbellekleme için işaretlenmiş herhangi bir tablonun Unique int key -> valueharitaya konabileceğini garanti eder .

  4. Karmaşık seçme sorguları - bu neredeyse hiçbir zaman gerçekleşmeyecektir, çünkü tüm küçük (<20-30K kayıtlar) tablo verileri uygulama düzeyinde önbelleğe alınır. Bu, uygulama kodunu yazarken hayatı biraz zorlaştırır (LINQ yazmak daha zordur), ancak veritabanı çok daha iyi vurulur:

    1. Liste görünümleri - SELECTyükte sorgu (her şey önbelleğe alınır) veya şuna benzer sorgular oluşturmaz:

      SELECT allcolumns FROM BigTable WHERE filter1 IN (val1, val2) AND filter2 IN (val11, val12)

      Diğer tüm gerekli değerler önbellek aramaları (O (1)) ile getirilir, bu nedenle karmaşık sorgular oluşturulmaz.

    2. Görünümleri düzenle - şöyle SELECTifadeler oluşturur :

      SELECT allcolumns FROM BigTable WHERE PKId = value1

(tüm filtreler ve değerler ints)


Sistemle üretilen vekil değerlere sahip sütunların kullanımı ile ilgili bazı mantıksal, fiziksel ve pratik yönler tartışıldığı için bu önemlilik mesajlarını bulabilirsiniz .
MDCCL

Yanıtlar:


19

Ek disk alanı (ve dolayısıyla bellek kullanımı ve G / Ç) dışında, bir tane gerekmeyen tablolara bile bir KİMLİK sütunu eklemenin gerçekten bir zararı yoktur (KİMLİK sütunu gerektirmeyen bir tablo örneği bir kullanıcıyı kendi izinleriyle eşleme gibi basit bir kavşak tablosudur).

2010'dan itibaren bir blog gönderisinde her tabloya körü körüne eklemeye karşı korkuyorum :

Ancak vekil anahtarların geçerli kullanım durumları vardır - sadece benzersizliği garanti ettiklerini varsaymamaya dikkat edin (bu bazen eklenirler - bir satırı benzersiz olarak tanımlamanın tek yolu olmamalıdır ). Bir ORM çerçevesi kullanmanız gerekiyorsa ve ORM çerçeveniz, gerçek anahtarınızın bir tamsayı olmadığı veya tek bir sütun olmadığı veya hiçbirinin olmadığı durumlarda bile tek sütunlu tamsayı anahtarları gerektiriyorsa, benzersiz kısıtlamalar / dizinler tanımladığınızdan emin olun gerçek anahtarlarınız için de.


Hızlı cevap için teşekkürler. Evet, uygulama bir ORM (EF) kullanır. Tek tamsayı sütun anahtarları gerektirmez, ancak bazı genel işlemleri çok daha kolay hale getirmek için bu kısıtlamayı getirdim (tasarım açısından). Ayrıca, tüm uygulama önbellekleri her şeyi haritalarda (sözlükler) depolar ve anahtar ile hızlı geri alma sağlar ve anahtarın benzersiz olması gerekir. Kılavuzları yerine ints'ı seçtiğimden, içine yerleştirdiğim herhangi bir tablo için KİMLİK kullanmak zorunda kalıyorum. Sabit değerler tabloları için IDENTITY gerekli değildir.
Alexei

Doğal anahtarlar üzerindeki teklik kontrolünden kaçınmayı gerektiren bazı durumlar olduğunu düşünüyorum. CBS verileriyle çalışan biri olarak, hemen akla gelen, doğal anahtarın sadece geometrinin kendisi veya geometrinin yanı sıra yabancı bir anahtar olduğu yerdir. Bir şeyleri kesin bir geometri ile aramak her zaman pratik olmayacaktır, bu nedenle üzerinde benzersiz bir kısıtlamanın çok fazla yardımcı olması olası değildir ve performans dezavantajları olabilir. Doğal anahtarın bir kısmı uzun bir metin sütunu ise aynı şey geçerli olabilir. Ama katılıyorum: pratik olduğunda, evet, doğal anahtar üzerinde benzersiz bir kısıtlama uygulanmalıdır.
jpmc26

13

Deneyimlerime göre, her tablo için ayrı bir kimlik kullanmanın ana ve ezici nedeni şudur:

Neredeyse her durumda müşterim , bazı dış, "doğal" alanların sonsuza dek benzersiz kalacağı ve belirli bir varlık için asla değişmeyeceği ve asla tekrar kullanılmayacağı anlayış aşamasında kan yeminini yemin ettiXYZBLARGH_ID . Birincil Anahtar özellikleri bozuldu. Sadece bu şekilde çalışmaz.

Daha sonra, bir DBA bakış açısından, DB'yi yavaşlatan veya şişiren şeyler kesinlikle satır başına 4 bayt (veya her neyse) değil, yanlış veya eksik dizinler, unutulmuş tablo / dizin yeniden düzenlemeleri, yanlış RAM / tablo alanı ayarlama parametreleri gibi şeyler , bind değişkenlerini kullanmayı ihmal ederek vb. Bunlar DB'yi ek bir ID sütunu değil 10, 100, 10000 faktörleriyle yavaşlatabilir.

Bu nedenle, satır başına ek 32 bitlik olmanın teknik, ölçülebilir bir dezavantajı olsa bile, kimliği kimliğinizi optimize edip edemeyeceğiniz değil, kimliğin gerekli olup olmayacağı sorusu değildir. bir noktada , muhtemelen değil. Ve bir yazılım geliştirme duruşundan (ORM örneğiniz gibi veya tasarımdaki tüm kimlikler aynı veri tipine sahip olduğunda yazılım geliştiricileri için bunu kolaylaştırdığı gerçeği) tüm "yumuşak" faydaları hesaba katmayacağım. .

Not: n:mİlişkili tablolar için ayrı bir kimliğe ihtiyacınız olmadığına dikkat edin, çünkü bu tablolar için ilişkili varlıkların kimlikleri birincil anahtar oluşturmalıdır. Karşı örnek, tuhaf bir nedenden ötürü aynı iki varlıkn:m arasında birden çok ilişkilendirmeye izin veren garip bir ilişkilendirmedir - bir PK oluşturmak için kendi kimlik sütunlarına ihtiyaç duyacaklardır. Yine de çok sütunlu PK'ları işleyemeyen ORM kütüphaneleri vardır, bu yüzden böyle bir kütüphane ile çalışmak zorunda olmaları durumunda geliştiricilere karşı yumuşak olmanın bir nedeni olacaktır.


2
"aynı iki varlık arasında birden fazla ilişkilendirmeye izin veren garip n: m derneği" gerçek hayatta çok yaygın. Örneğin, bir kişinin bir arabası var, sahiplik başladığında ve bittiğinde gereksinimler kaydedilecek şekilde değişir, (Bir kişi bir araba satabilir ve daha sonra geri satın alabilir ve yazılımınızı
kilitleyebilir

Evet, böyle bir şey, @IanRingrose.
AnoE

6

Her tabloya her zaman anlamsız bir ekstra sütun ekler ve yalnızca bu sütunları yabancı anahtar olarak referans alırsanız, veritabanını neredeyse kaçınılmaz olarak daha karmaşık ve kullanımı zor hale getireceksiniz. Etkili bir şekilde yabancı ilgi alanlarından kullanıcıların ilgisini çeken verileri kaldıracak ve kullanıcıyı / uygulamayı aynı bilgileri almak için fazladan birleştirme yapmaya zorlayacaksınız. Sorgular daha karmaşık hale gelir, optimize edicinin işi zorlaşır ve performans düşebilir.

Tablolarınız, diğerlerinden daha fazla "gerçek" verilerle daha az doldurulur. Bu nedenle veritabanını anlamak ve doğrulamak daha zor olacaktır. Ayrıca bazı yararlı kısıtlamaların uygulanmasını zor veya imkansız bulabilirsiniz (kısıtlamaların artık aynı tabloda bulunmayan birden fazla özelliği içereceği durumlarda).

Anahtarlarınızı daha dikkatli seçmenizi ve yalnızca iyi nedenleriniz varsa / olduğunda tamsayılar yapmanızı öneririm. Veritabanı tasarımlarınızı dogmatik kurallara dayanmak yerine iyi analiz, veri bütünlüğü, pratiklik ve doğrulanabilir sonuçlara dayandırın.


1
Ve yine de birçok sistem, bu tür problemlerden muzdarip olmadan her tabloda (örneğin, şimdiye kadar yazılmış hemen hemen her Ruby on Rails uygulaması) sentetik tamsayı birincil anahtarlara sahiptir. Ayrıca hiçbir zaman birincil anahtarlarda (hiçbir zaman olması gerekmeyen) değişiklikleri tüm yabancı anahtar tablolarına zorlamak zorunda kalmazlar.
David Aldridge

2
Soru olası dezavantajları sordu, dolayısıyla cevabım. Yedek anahtarların akıllıca kullanılırsa mantıklı olabileceğini inkar etmiyorum. Ancak, 3,4,5 (veya daha fazla) anlamsız yabancı anahtar içeren tablolar gördüm, bu nedenle bunlardan yararlı sonuçlar almak için 3,4,5 veya daha fazla birleşim gerektirdi. Daha pragmatik bir tasarım hiçbir birleşim gerektirmeyebilirdi.
nvogel

1
İnsanların böyle bir tasarıma sahip olduğu birincil sorun olan bu tür sorguların yürütülmesine ikna olmadım - sık sık itiraz ettikleri sorgunun yazılması.
David Aldridge

5

Çeşitli veritabanları ile yaşadığım deneyime göre, bir Tamsayı birincil anahtarı, hiçbir anahtarı tanımlanmamış uygulamalardan her zaman daha iyidir . Ya da yarım düzine varchar sütununu mantıksal olmayan garip yollarla birleştiren anahtarları var ... (iç çek)

Tamsayı PK'lardan GUID'lere geçen uygulamalar gördüm. Bunu yapma nedenleri, bazı durumlarda birden çok kaynak veritabanındaki verilerin birleştirilmesine ihtiyaç duyulmasıydı. Geliştiriciler, tüm anahtarları GUID'lere değiştirdiler, böylece birleştirme işleminin bir parçası olmayan tablolarda bile veri çarpışması korkusu olmadan gerçekleşebilir (bu tabloların gelecekteki bir birleştirmenin bir parçası olması durumunda).

Ayrı kaynaklardan veri birleştirmeyi planlamadığınız veya tamsayı boyut sınırlarınızı aşan verileriniz olmadıkça tamsayı PK'nın sizi ısırmayacağını söyleyebilirim - ekler için alan bitene kadar hepsi eğlenceli ve oyun .

Bununla birlikte, tablo bu şekilde daha sık sorgulanacaksa, kümelenmiş dizininizi PK'nız dışındaki bir sütuna ayarlamanın mantıklı olabileceğini söyleyeceğim . Ancak bu, özellikle güncellemelerin ve seçimlerin büyük bir kısmı PK değerlerine dayanıyorsa, dış kaynaklı bir durumdur.


2
Tüm anahtarları rehberlere değiştirmek korkunç bir gerekçe gibi görünüyor. Şu anda tüm vekil anahtarlar için kılavuzlar kullanan bir veritabanı ile çalışmak .. onun eğlenceli değil.
Andy

2
Hayır. GUID'leri kullanmak eğlenceli değildir. Onları sevmiyorum, ancak bazı kullanım durumlarında değerlerine saygı duyuyorum.
CaM

2

Bir kenara koymak:

  • Dini savaşlar (google vekil vs doğal anahtar)
  • Kümelenmiş dizinlerin tablolarınızda tanımlanmasının ayrı sorunu
  • Tüm verilerinizi önbelleğe almanın uygulanabilirliği

Uygun olan yerlerde toplu silme / güncelleme kullanmanız ve bu tür işlemleri desteklemek için dizinlere sahip olmanız koşuluyla, kullandığınız PK standardı nedeniyle sorun yaşayacağınızı düşünmüyorum.
Daha sonra EF, birleşimler vb. İle sorgular oluşturduysanız, doğal anahtar tabanlı bir depoda olduğu kadar verimli olmayacaklar, ancak her iki şekilde de kesin olarak söyleyecek kadar alan bilmiyorum.


4
Doğal bir anahtardaki bir birleştirmenin bir tamsayıdaki birleştirmeden daha verimli olacağı tek bir durum düşünemiyorum - birçok doğal anahtar 4 bayttan küçük olamaz ve eğer varsa, yeterince benzersiz olamaz Fark malzemesi yapmak için satırlar.
Aaron Bertrand

Yetkili, optimize edilebilir SQL için katılıyorum, ancak SQL jeneratörlerinin olası sınırlamalarından bahsediyordum. Bu alandaki tek deneyimim, EF'in kaşıkla beslenebileceği kapsamlı görüşler yaratması isteniyor - ancak .net geliştiricilerinin EF hakkında yeterince bilgi sahibi olmaması veya başka nedenler olması olası.
TH

@AaronBertrand Daha verimli olabilmelerinin tek yolunun bir birleştirmeye hiç ihtiyaç duyulmaması olduğunu söyleyebilirim. Doğal anahtarların kullanımını düşündüğüm tek yer ISO4127 para birimi kodları (insan tanınır) gibi standart kod listeleridir ve GBP, EUR vb. Para birimi kodundaki birincil veya alternatif anahtarın yabancı anahtarı olarak kullanabilirim tablo.
David Aldridge

@David Tabii ki, birleşmelerin gerekli olduğu durumlar hakkında konuşuyordum. Doğal anahtarın tüm ilgili tablolarda çoğaltılmasını istemediğim birçok durum var, çünkü doğal anahtarlar değişebilir ve bu acı verici bir şeydir.
Aaron Bertrand

Hmmm, cevabımın vekil üzerinde doğal yabancı anahtarları tanıtmak için nasıl yanlış anlaşılabileceğini görüyorum. Açıkçası, sadece onlardan bahsettim çünkü a) Alexei'nin "doğal anahtarları kullanmamamız bir sorun mu?" Sorusunu okudum. birden fazla perspektif olduğunu kabul etmem gerektiğini hissettim ve c) çünkü kullanılacak ORM özelliklerinin seçimi büyük ölçüde belirlediğini düşünürdüm (aslında bir fark yaratabilirse). Kendimi vekil yabancı anahtar kampındayım.
TH

2

Size rehberlik edecek birkaç faktör var,

  1. Tanımı ve özellikleri.

    Bir şey, görev veya fizik yasaları tarafından benzersiz olarak tanımlanırsa, bir yedek anahtarla zamanınızı boşa harcarsınız.

  2. Teklik.

    Kişisel akıl sağlığı, birleşme ve daha üst düzey veritabanı işlevselliği için (a) benzersiz sütun, (b) benzersiz sütun dizisine ihtiyacınız vardır

    Tüm yeterince normalleştirilmiş şemalar (1NF) aşağıdakilerden birini sağlar. Eğer yapmazlarsa , daima bir tane oluşturmalısınız. Pazar günü gönüllü olarak ayarlanmış bir listeniz varsa ve soyadı ve adı varsa, iki Joe Bobs'unuz olduğunu bilmek istersiniz.

  3. Uygulama ve optimizasyon.

    Bir int, karşılaştırma ve eşitlik için hızlı olan küçük bir veri formu olma eğilimindedir. Harmanlaması yerel ayara (konum ve dil) bağlı olan bir Unicode dizesiyle karşılaştırın. 4242'yi ASCII / UTF8 dizesinde saklamak 4 bayttır. Bir tamsayı olarak saklanması 2 bayta sığar.

Dezavantajlar söz konusu olduğunda birkaç faktörünüz var.

  1. Karışıklık ve belirsizlik.

    1. @Aaron Bertrand blog girişi bunu çok iyi özetliyor. Şartname ve görev tarafından bir OrderID sahip olmak ve sonra veritabanı uygulaması aracılığıyla bir " OrderID " uygulamak kendi kendini belgelemek değildir . Bazen bunu açıklığa kavuşturmak veya bir sözleşme oluşturmak zorundasınız, ancak bu muhtemelen karışıklık yaratacaktır.
  2. Uzay.

    Tamsayılar hala satıra boşluk ekler. Ve eğer onları kullanmıyorsanız bir amaç yoktur.

  3. Kümeleme.

    Verilerinizi yalnızca bir şekilde sipariş edebilirsiniz. Gerekli olmayan bir yedek anahtar dayatırsanız, bu şekilde mi yoksa doğal anahtarın şeklinde mi kümelenirsiniz?


Güzel ve kısa artıları ve eksileri.
Alexei

@Alexei teşekkürler, aradığınızı karşılıyorsa, seçili olarak işaretlemeyi düşünün. Ya da açıklama istemek.
Evan Carroll
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.