SQL Veritabanında Birincil Anahtar Olarak Dizeler


178

Veritabanlarına ve nasıl çalıştıklarına dair teorilere pek aşina değilim. Birincil Anahtarlar için Dizeleri tamsayılardan kullanmak performans açısından (ekleme / güncelleme / sorgulama) yavaş mı?

Yanıtlar:


191

Teknik olarak evet, ancak bir dize birincil anahtar olarak anlamlıysa, muhtemelen kullanmalısınız. Bu, tabloyu oluşturduğunuz tablonun boyutuna ve birincil anahtar olacak dizenin uzunluğuna bağlıdır (daha uzun dizeler == karşılaştırması daha zordur). Mutlaka milyonlarca satır içeren bir tablo için bir dize kullanmazdım, ancak daha küçük tablolarda bir dize kullanarak alacağınız performans yavaşlama miktarı, olmayan bir tamsayıya sahip olabileceğiniz baş ağrılarına minik olacaktır. verilerle ilgili hiçbir şey ifade etmiyor.


11
veritabanına bağlı olmaz mıydı? Düzgün dizinlenmiş bir dize bir sayıdan hiç değilse o kadar yavaş olmaz düşünürdüm?
Ryan Guill

2
Dikkate alınacak çok sayıda değişken olduğunu kabul ediyorum. (Sqlserver) dizine eklenmiş olsa bile, ortadan yüksek gençlere ve üzeri uzunluklara sahip dizeler kullanmayla ilgili gerçek performans sorunları gördük. Örneğin, bu donanımın üstesinden gelmek için doğru şeyler var.
kemiller2002

1
Yeterince adil. Bir dize mantıklıysa, kullanmanız gereken şey bu olsa kabul ediyorum. Ayrıca, bir autoincrement alanının işe yaramayacağı veritabanlarındaki GUID veya UUID alanları için kesinlikle zamanlar olduğunu söyleyebilirim.
Ryan Guill

7
Ayrıca, dizin karşılaştırmaları yaparken CHAR ve VARCHAR arasında genellikle çok büyük bir fark olduğunu unutmayın
Tom H

7
Bu cevabın yorumlarının sayısı, cevabın ne kadar eksik olduğunu netleştirir. Bahsedilen endeksleme kabul edilebilir minimum cevap olacaktır.
Pedro Rolo

74

Dizeleri birincil anahtar olarak kullanmayla ilgili bir başka sorun, dizin sürekli olarak sıralı bir sıraya konulduğu için, siparişin ortasında yeni bir anahtar oluşturulduğunda dizinin yeniden oluşturulması gerekir ... tamsayı, yeni anahtar dizinin sonuna eklenir.


2
Bu yeni uçlar için "sıcak noktalara" neden olabilir. Veritabanınızı düzgün bir şekilde yönettiğiniz sürece, ekler için sayfalarınızda fazladan boşluk olmalı ve sayfa bölünmeleri nadir olmalıdır.
Tom H

20
birincil anahtarlar kümelendiğinde. bunları da kümelenmemiş olarak oluşturabilirsiniz.
öğrenme

XID dizeleri sadece xid dizeleri kullanırsanız yardımcı olabilir
Sinaesthetic

22

Eklemenin dizinin ortasında gerçekleştiği kümelenmiş bir dizine sahip bir tabloya eklenenler, dizinin yeniden yazılmasına neden OLMAZ. Verileri içeren sayfaların yeniden yazılmasına neden olmaz. Sayfada satırın gideceği yer varsa, o sayfaya yerleştirilir. Tek sayfa, satırı sayfada doğru yere yerleştirmek için yeniden biçimlendirilecektir. Sayfa dolduğunda, sayfadaki satırların yarısı bir sayfaya ve yarısı diğer sayfaya giderken bir sayfa bölünmesi gerçekleşir. Daha sonra sayfalar, kümelenmiş dizine sahip bir tablo verisi içeren bağlantılı sayfalar listesine yeniden bağlanır. En fazla 2 sayfa veritabanı yazacaksınız.


İyi açıklama. Ama bu tüm SQL veritabanları için geçerli mi? Birincil anahtar olarak rastgele UUID kullanırken MySQL performans sorunlarını duydum.
hgoebl

13

Dizeler birleşmelerde daha yavaştır ve gerçek hayatta çok nadiren gerçekten benzersizdirler (olması gerekiyorsa bile). Tek avantaj, yalnızca adı almak için birincil tabloya katılıyorsanız, birleştirme sayısını azaltabilmeleridir. Bununla birlikte, dizeler de genellikle değişime tabidir, böylece şirket adı değiştiğinde veya kişi evlendiğinde ilgili tüm kayıtları düzeltmek zorunda kalır. Bu büyük bir performans isabeti olabilir ve bir şekilde ilişkili olması gereken tüm tablolar ilişkili değilse (bu düşündüğünüzden daha sık gerçekleşir), veri uyumsuzluklarınız da olabilir. Kaydın ömrü boyunca asla değişmeyecek bir tam sayı, veri bütünlüğü açısından ve performans açısından çok daha güvenli bir seçimdir. Doğal anahtarlar genellikle verilerin bakımı için o kadar iyi değildir.

Ayrıca, her iki dünyanın en iyisinin genellikle PK olarak bir otomatik azaltma anahtarı (veya bazı özel durumlarda, bir GUID) kullanmak ve daha sonra doğal anahtara benzersiz bir dizin koymak olduğunu belirtmek isterim. Daha hızlı birleştirme elde edersiniz, yinelenen kayıtlar alamazsınız ve bir şirket adı değiştiği için bir milyon çocuk kaydını güncellemeniz gerekmez.


26
PK'ler için iyi aday olan dizelerin kopyaları yoktur - aksi takdirde PK için iyi bir aday olmazlar. ICD-9 kodlarını, ülke kodlarını, VIN # numaralarını düşünün. Doğal anahtarlarla ilgili bir soruna örnek olarak bir ad kullanmak yanlış yönlendirilmiştir, çünkü ilk etapta asla aday olmamalıdırlar.
Tom H

6
@Tom H: ISO İlçe kodları değişir. [ en.wikipedia.org/wiki/ISO_3166-1#Editions_and_changes ] İlgili bir soruya yanıt olarak [ stackoverflow.com/questions/925266/… ] "BİRİNCİL ANAHTARLAR için benzersizliğinin kontrolünüz altında olduğundan emin olun"
Steve Schnepp

4
@SteveSchnepp: evet ve ISO bu değişikliği yönetmek için güvenilir bir kuruluştur. Öte yandan, artan tamsayı değerlerinin monotonik sırasını başkasınınkiyle birleştirmeniz gerektiğinde, tek başınıza olursunuz;)
gün

1
İsimlerin bir anahtar olarak kabul edilmemesi gerektiğini kabul ediyorum, sadece o zamanlar omany gördüm.
HLGEM

1
2 monotonik artan tamsayı dizisi önekleme veya sonlandırma ile birleştirilirken kolayca tamamlanır :)
Steve Schnepp

6

BENZERSİZ olduğu sürece birincil anahtar olarak ne kullandığınız önemli değildir. Hız veya iyi veritabanı tasarımı ile ilgileniyorsanız, veri çoğaltmayı planlamıyorsanız int öğesini kullanın, ardından bir GUID kullanın.

Bu bir erişim veritabanı veya bazı küçük bir uygulama ise o zaman kim gerçekten umurunda. Bence geliştiricilerin çoğunun eski int ya da ön cepheyi tokatlamasına neden olmamız, projelerin üzerimizde büyümenin bir yolu olması ve kendinize büyüme seçeneğini bırakmak istemenizdir.


5

Çok fazla değişken var. Tablonun büyüklüğüne, dizinlere, dize anahtar alanının doğasına bağlıdır ...

Genellikle tamsayılar daha hızlı olacaktır. Ancak fark, bakım için yeterince büyük olacak mı? Söylemesi zor.

Ayrıca, telleri seçme motivasyonunuz nedir? Sayısal otomatik artış tuşları da genellikle çok daha kolaydır . Anlambilim mi? Kolaylık? Çoğaltma / bağlantısı kesilme endişeleri? Buraya verdiğiniz yanıt seçeneklerinizi sınırlandırabilir. Bu aynı zamanda unuttuğunuz üçüncü bir "karma" seçeneği de akla getiriyor: Kılavuzlar.


hiç mantıklı değil, ne demek istiyorsun?
HLGEM

@HLGEM: Yazdığını anlarsam, bir dizüstü bilgisayarda oluşturulan kayıtları ana db ile senkronize etmek gibi bir şeydir.
Joel Coehoorn

Yani aynı varlıkları olan iki ayrı veritabanım var, kalıcı depolama amacıyla yalnızca bir tanesi daha az sıklıkta güncelleniyor. A Veritabanındaki "California" varlığını
sorgularsam,

1
Ve bir dizüstü bilgisayarda oluşturulan kayıtları aynı problemle senkronize etmek 'gibidir': bir yerde oluşturulan kayıtlar başka bir yerde oluşturulan kayıtlarla çakışmamalıdır. Burada olası bir çözüm Guid anahtarlarıdır.
Joel Coehoorn

5

Verilerin açıklandığı ve verilerin amaçlanan kullanımına uygun olduğu konusunda anlaşılan basit ve sağlam bir tasarıma sahip oluncaya kadar performans konusunda endişelenmeyin. Daha sonra performans sorunları ortaya çıkarsa, sistemi değiştirerek bunlarla başa çıkabilirsiniz.

Bu durumda, doğal bir birincil anahtar olarak bir dize ile gitmek neredeyse her zaman daha iyidir, ona güvenmenizi sağlar. Bir dize olup olmadığını düşünmeyin, dize oldukça kısa olduğu sürece, maksimum 25 karakter söyleyin. Performans açısından büyük bir bedel ödemezsiniz.

Veri girişi yapan kişiler veya otomatik veri kaynakları varsayılan doğal anahtar için her zaman bir değer sağlıyor mu yoksa bazen atlanıyor mu? Girdi verilerinde bazen yanlış mı oluyor? Öyleyse, hatalar nasıl algılanır ve düzeltilir?

Sorguları belirleyen programcılar ve etkileşimli kullanıcılar, istedikleri şeyi elde etmek için doğal anahtarı kullanabilir mi?

Doğal anahtara güvenemiyorsanız, bir vekil icat edin. Bir vekil icat ederseniz, bir tamsayı da icat edebilirsiniz. Sonra kullanıcı topluluğundan vekil gizlemek için ne için endişelenmeniz gerekir. Yedek anahtarı gizlemeyen bazı geliştiriciler, pişman olmaya geldi.


3

Endeksler birçok karşılaştırma anlamına gelir.

Tipik olarak, dizeler tamsayılardan daha uzundur ve karşılaştırma için karşılaştırma kuralları uygulanabilir, bu nedenle dizeleri karşılaştırmak genellikle tamsayıları karşılaştırmaktan daha hesaplama açısından yoğun bir iştir.

Bununla birlikte, bazen, bir dizeyi birincil anahtar olarak kullanmak, bir string to numerical idtabloya fazladan birleştirme yapmaktan daha hızlıdır .


2

Evet, ancak milyonlarca satır olmasını beklemediğiniz sürece, daha yavaş olduğu için dize tabanlı bir anahtar kullanmamak genellikle "erken optimizasyon" dur. Sonuçta, dizeler büyük sayılar olarak kaydedilirken, sayısal tuşlar genellikle daha küçük sayılar olarak saklanır.

Dikkat edilmesi gereken bir şey, herhangi bir anahtar üzerinde dizinleri kümelemişseniz ve dizinde sıralı olmayan çok sayıda ekleme yapıyorsanız. Yazılan her satır, dizinin yeniden yazılmasına neden olur. toplu ekler yapıyorsanız, bu işlemi gerçekten yavaşlatabilir.


2

PK sütunları için tamsayı kullanmanın iki nedeni:

  1. Otomatik olarak artan tam sayı alanı için kimlik ayarlayabiliriz.

  2. PKs oluşturduğumuzda, db verileri tabloda depolanmadan önce sıralayan bir dizin (Küme veya Kümesiz) oluşturur. PK üzerinde bir kimlik kullanarak, optimize edicinin bir kaydı kaydetmeden önce sıralama düzenini kontrol etmesi gerekmez. Bu, büyük tablolarda performansı artırır.


1

Bir dizeyi birincil anahtar olarak kullanma nedeniniz nedir?

Sadece birincil anahtar otomatik artan bir tamsayı alanına ayarlamak ve dize alanına bir dizin koymak.

Bu şekilde masaya arama yaparsanız göreceli olarak hızlı olmalılar ve tüm birleşimleriniz ve normal aramalarınız hızlarından etkilenmeyecektir.

Dizine eklenen dize alanının miktarını da denetleyebilirsiniz. Başka bir deyişle, bunun yeterli olacağını düşünüyorsanız "yalnızca ilk 5 karakteri dizine ekle" diyebilirsiniz. Veya verileriniz nispeten benzerse, tüm alanı dizine ekleyebilirsiniz.


3
Bence herhangi bir zekayı bir anahtara koymak bela istiyor. Eşsiz kalacaklar mı? Tüm hesap numaralarını devletin kısaltmasıyla başlayıp, sadece müşteri hamlesine başladılar mı? Bir alanın güncellenmesi - sorun değil - hesap numarasına bağlı tüm tablolar - ne dağınıklık.
JeffO

1
Dizeyi PK olarak kullanma örneği bir ayar tablosu olabilir. örneğin settingNamePK, isUserEditable, isCustomerEditable vb. Ayar davranışını değiştirmek istiyorsanız "UPDATE setting SET ... WHERE settingNamePK = 'dailyWorkObligation'", ID'leri kullanmak ve kimliklerin eşleştirildiği bir yerde saklamaktan çok daha hoştur. Tabii ki bir tamsayı PK'nız olabilir ve başka bir benzersiz anahtar olarak ayar adına sahip olabilirsiniz.
MeatPopsicle

Birincil anahtar otomatik olarak artırılan bir tamsayı olduğu için, ekler de hızlarından etkilenmemelidir?
Dennis

Meraklı Rails geliştiricileri için, bir dizin uzunluğunu nasıl belirleyeceğiniz aşağıda açıklanmıştır . SQLite'ın dizin uzunluğunu desteklemediğini unutmayın.
Dennis

1

Performans açısından - Evet dize (PK), tamsayı (PK) kullanılarak elde edilen performansla karşılaştırıldığında performansı yavaşlatır; burada PK ---> Birincil Anahtar.

Gereksinim açısından - Bu, sorunuzun bir parçası olmasa da, bahsetmek istiyorum. Farklı tablolarda devasa veri işlerken, genellikle belirli bir tablo için ayarlanabilecek olası anahtar kümesini ararız. Bunun başlıca nedeni çok sayıda tablo olması ve çoğunlukla her tablo veya bazı tabloların bir ilişkiyle (Yabancı Anahtar kavramı) birbiriyle ilişkili olmasıdır. Bu nedenle, birincil anahtar olarak her zaman bir tamsayı seçemeyiz, bunun yerine bu tabloların birincil anahtarı olarak 3, 4 veya 5 özniteliklerin bir kombinasyonunu kullanıyoruz. Ve bu anahtarlar, kayıtları başka bir tabloyla ilişkilendirdiğimizde yabancı anahtar olarak kullanılabilir. Bu, gerektiğinde kayıtların farklı tablolar arasında ilişkilendirilmesini yararlı kılar.

Bu nedenle Optimal Kullanım için - Her zaman 1 veya 2 dize özniteliğine sahip 1 veya 2 tamsayının bir kombinasyonunu yaparız, ancak yine de yalnızca gerekliyse.


0

Veritabanında dize ile ilgili çok büyük bir yanlış anlama olabilir. Hemen hemen herkes sayıların veritabanı sunumunun dizelerden daha kompakt olduğunu düşünmektedir. Onlar db-s sayıları bellekte temsil olduğunu düşünüyorum. Ama bu doğru değil. Çoğu durumda sayı temsili, diğerine göre bir dizge benzeri temsile daha yakındır.

Sayı veya dizgeyi kullanma hızı, türün kendisinden ziyade dizinlemeye bağlıdır.


0

Varsayılan olarak ASPNetUserIds 128 karakter dizgisidir ve performans iyi durumdadır.

Anahtarın tabloda benzersiz olması GEREKİR ise, Anahtar olmalıdır. İşte nedeni;

birincil dize anahtarı = DB ilişkilerini düzeltin, 1 dize anahtarı (birincil) ve 1 dize Dizin (Birincil).

Diğer seçenek tipik bir int Anahtar olmakla dize eğer HAS benzersiz olması yine muhtemelen validate nedeniyle durmaksızın sorgular bir dizin eklemek veya eşsiz olmadığını kontrol etmek gerekir.

Bu yüzden bir int kimlik anahtarı = Hatalı DB İlişkileri, 1 int anahtarı (Birincil), 1 int dizini (Birincil), Muhtemelen benzersiz bir dize Dizini kullanmak ve aynı dizeyi manuel olarak doğrulamak zorunda değilsiniz (belki bir sql denetimi gibi bir şey) ).

Birincil anahtar için bir dize üzerinde bir int kullanarak daha iyi performans elde etmek için, dize zaman HAS benzersiz olması, çok garip bir durum olması gerekir. Her zaman string anahtarları kullanmayı tercih ettim. Eğer kadar da başparmak iyi bir kural olarak, bir veritabanı denormalize yok İHTİYACINIZ için.

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.