Yaylı anahtarların kullanımı neden genellikle kötü bir fikir olarak kabul edilir?


24

Bu beni bir süredir rahatsız ediyor. Verilerin, karma tablolar, programcılar, kitaplar ve makaleler gibi yapılarda depolanması söz konusu olduğunda, söz konusu yapılardaki elemanların String değerleri ile indekslenmesinin kötü bir uygulama olarak kabul edilmesinde ısrar etmektedir. Ancak, şu ana kadar, NEDEN kötü bir uygulama olarak kabul edildiğini açıklamak için böyle bir kaynak bulamadım. Programlama diline bağlı mı? Altta yatan çerçevede? Uygulamada mı?

Yardımcı olursa iki basit örnek alın:

Satırların bir String birincil anahtar tarafından indekslendiği bir SQL benzeri tablo.

Anahtarların Dizeleri olduğu bir .NET Sözlüğü.


9
Dize tuşlarına sahip olmak genel olarak kötü bir fikir değildir. Bu ifadelerin daha iyi bir anahtar tipinin mevcut olduğu bir bağlamda yapıldığından şüpheleniyorum. Her zaman dize tuşları ile .net sözlükler var. Bu iddianın bazı örneklerini verebilir misiniz?
KodlarInChaos

3
Genellikle bir nesnenin / satırın ömrü boyunca değişmeyen birincil anahtarlar istersiniz. Örneğin username, bir userstablonun birincil anahtarı olarak muhtemelen en iyi fikir değildir ve bir otomatik artış kimliği tercih edersiniz. Ama bu usernamebir dize sadece tesadüfidir, değişken bir özellik olmak ana konudur
CodesInChaos

Bir veritabanında, tamsayıların aksine dizeleri nasıl indeksleyeceğinizi düşünün.

@CodesInChaos Keşke çoğu vakayı nerede bulduğumu hatırlayabilsem diyorum ama şimdilik bana sorunu hatırlatan biti yapıştırabilirim. Oyun diyaloglarını tartışan ve dünyayla ilgili gerçekleri <key = string, value = object> çiftlerinde saklayan Valve tarafından yapılan bir GDC slayt gösterisinden yapıldı.

2
Dizeler iyi. Sadece 'sihirli' dizeleri değil. Bu nedenle, bir karma tablosu kullanırken, kodunuzda çıplak dizeler olmadığından emin olun. Büyük metin değerlerini anahtar olarak kullanmamalısınız çünkü iyi performans göstermezler, ancak çoğu gerçek dünyada kısa metin dizeleri tam sayı kadar hızlıdır (büyük veritabanları değildir). Alternatif anahtarlar da kullanabilirsiniz; örneğin, birincil anahtar bir sayıdır, ancak aynı zamanda benzersiz bir 'sümük' veya benzersiz bir dize vardır.
ipaul

Yanıtlar:


17

Her şey temelde iki şeyle ilgili olmalı:

1) Arama hızı (örneğin, tamsayıların çok daha iyi olduğu yerlerde)

2) Dizinlerin boyutu (dizge dizinlerinin patlayacağı yer)

Şimdi her şey sizin ihtiyaçlarınıza ve veri setinin boyutuna bağlı. Bir masa veya koleksiyonun içinde 10-20 öğe varsa, anahtarın türü ilgisizdir. Bir dize tuşu ile bile çok hızlı olacak.

PS Sorunuzla ilgili olmayabilir, ancak Kılavuzların veritabanı anahtarları için de kötü olduğu kabul edilir (16 bayt Kılavuzu ile 4 bayt tamsayısı). Büyük veri hacimlerinde Kılavuzlar aramayı yavaşlatır.


Her zaman değil - artan GUID'ler mümkündür. Dizinler hala daha büyük olacak, ancak arama cezası neredeyse kadar kötü olmayacak.
Sam

7
Aslında onlar iyi. Zaman diski IO zamanı ile bellekteki değerleri karşılaştırmak arasındaki ilişkiye bakmak zorundasınız. Disk erişim zamanları bellek karşılaştırmasını etkilediğinden, veritabanı performansını analiz etmede gerçekten önemli olan tek şey IO. Anahtarın bir GUID, dize veya bir tamsayı olup olmadığı gerçekten kritik değildir. Dizin boyutu, bir sayfaya kaç dizin değerinin sığdığını etkiler; ancak anahtarın 4 baytlık bir int (yeterince büyük olmayabilir ve istemci tarafından üretilemez) veya 16 baytlık bir değer olup olmadığı önemli bir sorun değildir. Bazı veritabanlarında rowId'ler 16 bayt boyutunda olabilir.
ipaul

9

Dizeleri anahtar olarak kullanmakla veya daha doğru bir şekilde, dizge değişmezlerini anahtar olarak kullanmak, saf performans / verimlilik nedenlerini bir kenara bırakmakla ilgili bir sorun daha var. Yazım hataları. Dize değişmezlerini bir sözlükte anahtar olarak kullanırsanız, biri "ReceiverId"haline geldiğinde kendinizi kötü bir sürprizle hazırlarsınız "RecieverId". Anahtar değerleri kaydetmek için sabitleri ayarlayın ve sözlüğe eriştiğinizde tekrar kullanın.

Önemsiz ve açık, söyleyebileceğiniz gibi, web'deki çarpıcı sayıda .NET kodu örneği, bu şüpheli uygulamanın yayılmasını sağlayan string değişmezlerini kullanıyor. ASP.NET, tüm oturumları, kod tabanı boyunca yayılmış ViewStates ve QueryParams ile burada özellikle suçlu.


Önemsiz değil IMHO. Ayrıca anahtarların olduğu "1"ve "1 "aynı tabloda olan durumları gördüm .
pswg

Karışımdaki büyük / küçük harf duyarlılığını da atarken, daha da eğlenceli. Kendim de dahil olmak üzere bir sürü insan doğrudan oraya rastladım.
Tony Hopkinson

Sabitleri kullanmaktan bile daha iyi, en azından C # ifadesi yerine İfadeleri kullanıyor. Bu şekilde, dizelerinizi yöntem / özellik vb. İsimlerinden oluşturabilirsiniz, böylece dizge aramalarınız güvenli ve refactor dostu olur.
GoatInTheMachine

4

Burada çok fazla travma var. Aslında string string'leri sıkça kullanıyorum, fakat çoğu zaman birleşim için yedek ikincil anahtarları da ekliyorum (tabii ki MySQL kullanıyor olsaydım bunun tersi olur). Ancak yapmadığım durumlar var.

Öncelikle db'nin bu durumu iyi idare edebileceği doğal anahtarlar olarak birincil anahtar olarak beyan etmenin hayranıyım (örneğin PostgreSQL). Bu normalleşmeye yardımcı olur ve daha net veritabanı tasarımı sağlar. Vekil tuşlar katılmayı kolaylaştırır.

Genellikle vekil anahtarlar eklememin iki nedeni var:

  1. Doğal bir anahtarın ne olduğu her zaman net değildir. Bazen bunlar değişmeli. Birleştirme ve referans bütünlüğü için kullanıldığında doğal, bileşik bir anahtarı değiştirmek karmaşıktır ve hataya açıktır.

  2. Kompozit anahtarlarda birleştirme performansı sorunludur ve bir kez doğal anahtar yolundan aşağıya indiğinizde, burada sıkışıp kalırsınız.

Doğal anahtarın tanımlayıcı olduğu durumlarda, tek sütun ve metin, ancak genellikle dize anahtarına katılırım. Bunu yapmamın nedeni, bunun genellikle araştırmaya katılmaktan kaçınmasıdır. En yaygın kullanım, enum tiplerinin kullanım durumlarında uygun db tasarımı sağlamaktır. Çoğu durumda, bu do not ekstra rutin sorguları için katılmak gerektirir. Öyleyse, bu durumda, birleştirme tuşları gibi dize tuşları mükemmel anlamlıdır.

Örneğin, LedgerSMB'de hesap kategorilerini saklıyoruz. Bunlar string referansı ile tanımlanır ve bazı diğer veriler bir hesabı etkileyebilecek kategorizasyonların kombinasyonları ile ilgili kuralları uygulamak için kullanılan string referansı ile birlikte saklanır. Mantığa ihtiyaç duyulan tek zaman, bir grup kategoriyi kaydederken, dize anahtarına katılıyoruz.

Neden varsayılanın tamsayı anahtarları olacağı konusunda, bunun sadece indeks büyüklüğünde bir soru olduğunu sanmıyorum. Önemli bir konu, anahtarların yönetimidir. Anahtar rastgele olduğundan ve milyonlarca kayıtla başa çıkabildiğiniz için, benzersiz karakter dizileri oluşturmanın bir yolunu bulmanız gerekir. İnsanların bunun için UUID kullandığı durumlar var, ancak sıfır olmayan bir UUID çarpışma olasılığı var ve milyarlarca kaydın saklandığı yerlerde, bu şans artmış tamsayı tipleriyle çarpışma şansı sıfırken gerçekten görülebilecek kadar yüksek hale geliyor tanım olarak.


Tamsayı türünü sıfıra geri sarmayı başarırsanız, sıfır değil. İmzasız bir 32-bit türü için, yalnızca 4G uzakta, bu da “milyarlarca kayıt” ile rahatsız edici bir şekilde yakın…
Donal Fellows

"Etrafına sarılmak yerine hata" diyebileceğiniz bir db varsa sıfırdır. Her halükarda, artan tamsayılı çarpışma olasılığını, sözde rasgele değerlere göre yönetmek daha kolaydır.
Chris Travers

1

Dizeleri anahtar olarak kullanmanın, özellikle de sql benzeri tablolara gelince, bazı olası sorunları vardır. @Bunny tarafından belirtildiği gibi, tablonuzun indeksleri daha büyük olacak, ama bence daha anlamlı, tablonun herhangi bir yabancı anahtar ilişkisi daha hafif (tamsayı) bir tanımlayıcının aksine dizgiyi içermesi için BOTH tablolarını içerecektir. . İlki referanslara sahip daha fazla tablo olduğunu tespit ederseniz, dize anahtarları veritabanınız boyunca çoğaltılacaktır.


1

Kendi başına fena bir fikir değil, genellikle 20 / 20'de zayıf bir tasarım uyumu ile. İpin esnekliği ve aralığı ile ek maliyet ve karmaşıklık.

Tamsayı iş aralığı akıllıca yapıyorsa ve pahalı işlemenin büyük kısmının tamsayıyı neyi temsil ettiğini bilmesi gerekmiyorsa, birini kullanın.


0

Bir şekilde yanlış veriyi bir Hashtable'dan aldın.

"DaytimeTelephone" veya "EveningTelephone" mı demek istediniz?

veya

Bunu mu demek istediniz: 1234567 veya 1234576?

Numaralar makine için tartışmalı olarak daha verimli olmasına rağmen , işler ters gittiğinde (ve yaptıkları zaman), sizin ve benim neye benzemekte ve ne olduğunu ve bu noktada, birkaç byte'lık depolama tasarrufu ve birkaç mikro (nano?) - işlem saniyeleri her seferinde netlik kaybeder .


1
Ve böylece, sihirli sayıyı temsil etmek için kodunuzdaki sabitin ismini kullanarak, bir sabitler listesiyle bitirdiniz ... Java onu daha da soyutlamak için kurtarmaya çağırıyor ve sizi yalnızca ismiyle bırakarak sıralamayı koyuyor haritalama görünmez.
jwenting

-1

Bir sürü takas ve doğru cevap yok. Birçok programcı veritabanında string tuşlarını kullanmayı asla düşünmezdi çünkü karmaşanın ve bir veritabanının nasıl çalıştığının farkında değiller. Dize tuşları, son derece kararlı oldukları ya da anlamsız oldukları (suretler) olduğu sürece, birçok durumda iyi bir tasarım tercihidir.


2
Bu cevap, daha önce söylenen diğer cevaplarda söylenmemiş olan hiçbir şeyi eklemez.
Martijn Pieters

-2

dize anahtarı, yaklaşık 10-100 kısa dize kaydının bulunduğu tabloya bakıldığında mantıklı olacaktır; ilgili veriler daha okunaklıdır + örneğin izlemeyi değiştir (sayısal / kılavuz kimliği ile string, örneğin "Yönetici"); btw, ASP.NET Üyelik veritabanı, AspNetRoles için dize anahtarlarını kullanır.

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.