PRIMARY KEY veya UNIQUE sütun olarak NVARCHAR sütunu


11

Bir SQL Server 2012 veritabanı geliştiriyorum ve birincil anahtarlar olarak nvarchar sütunları hakkında bir şüphem var.

Bu tablo var:

CREATE TABLE [dbo].[CODES]
(
    [ID_CODE] [bigint] IDENTITY(1,1) NOT NULL,
    [CODE_LEVEL] [tinyint] NOT NULL,
    [CODE] [nvarchar](20) NOT NULL,
    [FLAG] [tinyint] NOT NULL,
    [IS_TRANSMITTED] [bit] NOT NULL DEFAULT 0,
     CONSTRAINT [PK_CODES] PRIMARY KEY CLUSTERED 
    (
        [CODE_LEVEL] ASC,
        [CODE] ASC
    )
)

Ama şimdi [CODE]sütunu birincil anahtar olarak kullanmak ve [ID_CODE]sütunu kaldırmak istiyorum .

NVARCHAROlarak bir sütun varsa herhangi bir sorun veya ceza var PRIMARY KEYmı?

[CODE]sütun değeri benzersiz olmalıdır, bu yüzden ben UNIQUEbu sütuna bir kısıtlama ayarlayabilirsiniz düşündüm .

[CODE]Birincil anahtar olarak kullanmak zorunda mıyım yoksa sütunda bir UNIQUEkısıtlama belirlemem daha iyi olur [CODE]mu?


1
Dikkate değer oldukça önemli olan, tablonuzda kaç satır olacağıdır?
James Z

Bu kendi başına bir cevap değil , ancak CODEsütununuzun benzersiz olması gerektiğini, ancak Birincil Anahtar olmadığını düşünmeye meyilliyim . Bilgi taşıdığından şüpheleniyorum. Bu bilgiler herhangi bir şekilde değiştirilebilirse, o zaman CODEdeğişmeli veya güncel olmamalıdır. Bu Birincil Anahtarınızı geçici hale getirir ve bunun sonunun iyi olduğunu göremiyorum. PK'nızın bir anahtar olmasına izin vermek en iyisidir ve KOD'nuz istediklerini yapabilir. Sadece bir fikir.
Manngo

@ Manngo, yorumunuz için teşekkürler. Evet, bu şekilde yaptım: ID_CODE birincil anahtar ve CODE BENZERSİZ.
VansFannel

Yanıtlar:


13

Evet, kesinlikle Birincil Anahtar için sayısal bir tür yerine bir dize kullanmanın olumsuz sonuçları vardır ve dahası, bu PK Kümelenmişse (gerçekten sizin durumunuzda). Ancak, bir dize alanı kullanmanın etkilerini görme derecesi a) bu tabloda kaç satır olduğu ve b) diğer tablolardaki kaç satırın bu PK'ye Yabancı Anahtarlı olduğu işlevidir. Bu tabloda yalnızca 10k satırınız ve bu tablo aracılığıyla FK'nin bu tabloya göre koyduğu diğer birkaç tabloda 100k satırınız varsa, belki de bu kadar fark edilmeyecektir. Ancak satır sayısı arttıkça bu etkiler kesinlikle daha belirgin hale gelir.

Kümelenmiş bir Dizindeki alanların Kümelenmemiş Dizinlere aktarıldığını düşünmeniz gerekir. Yani sadece satır başına 40 bayta değil, (40 * bazı_sayılı) bayta da bakıyorsunuz. Ve herhangi bir FK tablosunda, satırda aynı 40 bayt var artı daha sık olarak JOIN'lerde kullanıldığı gibi bu alanda Kümelenmemiş bir dizin olacak, bu yüzden FK'nin herhangi bir tabloda gerçekten iki katına çıkacak. Bu. Biri 40 bayt * 1 milyon satır * 10 kopyasının endişelenecek bir şey olmadığını düşünmeye eğilimliyse, lütfen Disk Ucuzdur makalemi görün ! ORLY? bu karardan etkilenen alanların tümünü (veya en azından çoğunu) ayrıntılı olarak açıklar.

Dikkate almak başka bir şey filtreleme ve ikili Harmanlama (Ben genellikle küçük harfe duyarlı değildir veritabanı varsayılan kullandığınız varsayılmaktadır) kullanmayan özellikle iplerin üzerinde tasnif kullanırken daha (yani uzun sürer) çok daha az verimli olmasıdır INT/ BIGINT. Bu, bu alana filtre uygulayan / birleştiren / sıralayan tüm sorguları etkiler.

Bu nedenle, CHAR(5)Kümelenmiş bir PK için benzer bir şey kullanmak muhtemelen iyi olurdu, ancak çoğunlukla da COLLATE Latin1_General_100_BIN2(veya bunun gibi bir şeyle) tanımlanmışsa.

Ve değeri [CODE]hiç değişebilir mi? Cevabınız evet ise, onu PK olarak kullanmamanız için daha fazla sebep vardır (FK'leri ayarlamış olsanız bile ON UPDATE CASCADE). Eğer bunu değiştiremez veya hiç değiştirmeyecekse bu iyidir, ama yine de Kümelenmiş PK olarak kullanmamak için yeterli neden vardır.

Tabii ki, soru şu anda PK'nizde zaten bu alana sahip gibi göründüğü için yanlış ifade edilmiş olabilir.

Ne olursa olsun, en iyi seçeneğiniz, [ID_CODE]Kümelenmiş PK olarak kullanmak, bu alanı FK olarak ilgili tablolarda kullanmak ve [CODE]bir UNIQUE INDEX(alternatif olarak "alternatif anahtar" olduğu anlamına gelir) olarak kullanmaktır.


Güncelleme
Bu yanıta yapılan bir yorumda bu soruya dayalı biraz daha bilgi:

[ID_CODE], PRIMARY KEY olarak, tabloya bakmak için [CODE] sütununu kullanırsam en iyi seçenek midir?

Bu, bazıları daha önce bahsettiğim, ancak yeniden ifade edeceğim birçok faktöre bağlıdır:

Birincil Anahtar, herhangi bir Yabancı Anahtar tarafından başvurulsun veya edilmesin, ayrı satırın nasıl tanımlandığıdır. Sisteminizin satırı dahili olarak nasıl tanımladığı, kullanıcılarınızın kendilerini / o satırı nasıl tanımladığı ile aynı olmak zorunda değildir. Benzersiz veri ile herhangi bir NOT NULL sütun olabilir çalışır, ancak PK, özellikle, aslında, herhangi FKS tarafından başvurulan, dikkate pratiklik sorunları vardır. Örneğin GUID'ler benzersizdir ve bazı insanlar bunları çeşitli nedenlerle kullanmayı gerçekten severler, ancak Kümelenmiş Dizinler için oldukça kötüdürler ( NEWSEQUENTIALIDdaha iyidir, ancak mükemmel değildir). Öte yandan, GUID'ler alternatif anahtarlar kadar iyidir ve uygulama tarafından satırı aramak için kullanılır, ancak JOIN'ler hala bir INT (veya benzeri) PK kullanılarak yapılır.

Şimdiye kadar bize [CODE]alanın sisteme tüm açılardan nasıl uyduğunu söylemediniz , şu andan itibaren satırlara nasıl baktığınızdan bahsediyorsunuz, ancak bu tüm sorgular için mi yoksa sadece bazıları için mi? Dolayısıyla:

  • [CODE]Değer ile ilgili olarak :

    • Nasıl üretilir?
    • Artımlı mı yoksa psuedo rastgele mi?
    • Aynı uzunluk mu yoksa değişen uzunluk mu?
    • Hangi karakterler kullanılıyor?
    • Alfabetik karakterler kullanılıyorsa: büyük / küçük harfe duyarlı mı yoksa duyarsız mı?
    • Takıldıktan sonra hiç değişebilir mi?
  • Bu tablo ile ilgili olarak:

    • Bu tabloya başka bir tablo FK ekliyor mu? Yoksa açıkça Yabancı Anahtarlı olmasa bile bu alanlar ( [CODE]veya [ID_CODE]) diğer tablolarda mı kullanılıyor?
    • Tek [CODE] tek satırları almak için tek alan kullanılıyorsa, [ID_CODE]alan hangi amaca hizmet eder? Kullanılmıyorsa, neden ilk etapta (bu, " [CODE]Alan hiç değişebilir mi?" Cevabına bağlı olabilir )?
    • Bu tabloda kaç satır var?
    • Bu tabloya başvurmak için başka tablolar varsa, her birinde kaç ve kaç satır var?
    • Bu tablo için dizinler nelerdir?

Bu karar sadece "NVARCHAR evet mi hayır mı?" Genel olarak konuşmanın iyi bir fikir olduğunu bulamadığımı tekrar söyleyeceğim, ama kesinlikle iyi olduğu zamanlar var. Bu tablodaki çok az alan göz önüne alındığında, daha fazla veya en azından çok fazla dizin olması olası değildir. Bu nedenle [CODE], Kümelenmiş Dizin olarak her iki şekilde de iyi olabilirsiniz . Ve başka hiçbir tablo bu tabloya gönderme yapmıyorsa, PK yapmak iyi olabilir. Ancak, diğer tablolar bu tabloya başvuruyorsa, o zaman [ID_CODE]Kümelenmemiş olsa bile alanı PK olarak seçerdim.


Anonim downvoter (aynı zamanda @noIDonthissystem'in cevabını da düşürmüş gibi görünüyor) herhangi bir yapıcı eleştiri sunmaya veya kusurlu bir mantığa dikkat çeker mi?
Solomon Rutzky

Cevabınız için teşekkürler. Mı [ID_CODE]olarak, PRIMARY KEYben kullanım eğer en iyi seçenek, [CODE]kolon tabloda arama yapmak için?
VansFannel

@VansFannel lütfen güncellememe bakın. Teşekkürler.
Solomon Rutzky

Bu dba topluluğuna katılıp bu yanıtı değerlendirdim.
Ahmet Arslan

6

Kavramları ayırmanız gerekir:

  • birincil anahtar bir tasarım konsepti, tablodaki girdilerin mantıksal bir özelliğidir. Tablo girişinin ömrü boyunca değişmez olmalı ve girişe başvurmak için uygulamada kullanılan anahtar olmalıdır.

  • kümelenmiş dizin bir depolama kavramı, fiziksel bir özelliktir. Sorgular için en yaygın erişim yolu olmalı, çoğu durumda kapsayan dizin olarak tatmin etmeye ve mümkün olduğunca çok sayıda aralık sorgusunu karşılamaya hizmet etmelidir.

Birincil anahtarın kümelenmiş dizin olması gerekmez. ID_CODEPK ve (CODE_LEVEL, CODE)kümelenmiş anahtar olarak sahip olabilirsiniz . Ya da tam tersi.

Daha büyük anahtar, dizin sayfalarında daha düşük yoğunluk ve kümelenmemiş tüm dizinlerde tüketilen daha büyük boyut anlamına geldiğinden, daha büyük bir kümelenmiş anahtarın bazı olumsuz yankıları vardır. zaten bu konuya tonlarca mürekkep dökülmüş. başlamak kümeleme anahtar için fazla hususlar - kümelenmiş dizin tartışma devam ediyor! .

Ancak konunun özü, kümelenmiş dizin anahtarı seçiminin öncelikle bir ödünleşim olmasıdır. Bir yandan performanstaki genel yansımalarıyla depolama boyut gereksinimlerine sahip (-> daha büyük boyut - büyük tuşu> Daha fazla IO ve IO bant genişliği muhtemelen sahip olduğunuz en kıt kaynak). Öte yandan, yer tasarrufu adına yanlış kümelenmiş anahtarın seçilmesi, genellikle geniş bir anahtardan kaynaklanan sorunlardan daha kötü olan sorgu performansı sonuçlarına neden olabilir.

Birincil anahtar seçimine gelince, bu bir sorun bile olmamalıdır: veri modeliniz, uygulama mantığınız birincil anahtarın ne olduğunu belirlemelidir.

Söyleniyor, benim 2c: NVARCHAR(20)olduğunu değil geniş. Büyük bir tablo için bile mükemmel kabul edilebilir bir kümelenmiş anahtar boyutudur.


Cevabınız için teşekkürler. Is [ID_CODE]gibi PRIMARY KEY, en iyi seçenek ben kullanımı ise [CODE](belki ve sütun [CODE_LEVEL]) tabloda arama yapmak için?
VansFannel

@VansFannel buna sadece siz cevap verebilirsiniz.
Remus Rusanu

Ama sizce ...
VansFannel

2
Benim düşüncem, tablonun ve tüm endekslerin tam DDL'sini, onu gösteren yabancı anahtarları, tahmini satır sayısını, beklenen sorgu iş yükünü, uygulama beklenen SLA'ları ve donanım ve lisanslama için mevcut olan en az bütçeyi değil düşünmek zorunda kalacak.
Remus Rusanu

Teşekkürler. [CODE]Sütunu PRIMARY KEY olarak kullanacağım .
VansFannel

4

Asla kimsenin nvarchar(20)veritabanımda PK olması için izin vermem. Disk alanınızı ve önbellek kaybettiniz. Bu tablodaki tüm dizinler ve tablodaki tüm FK'ler bu geniş değeri çoğaltır. Belki haklı çıkarsa bir karakter (20). Ne tür veriler depolamaya çalışıyorsunuz CODE? Gerçekten nvarchar karakterleri saklamanız gerekiyor mu? PK'ları kullanıcılar tarafından görülmeyen "dahili" değerler yapmaya eğilimliyim ve görüntülenen değerleri ayrı tutmaya çalışıyorum. Görüntülenen değerlerin bazen değiştirilmesi gerekebilir, bu da PKs + FK'lerle çok sorunlu hale gelir.

Ayrıca, bir 'bigint kimliğinin (1,1)' 9,223,372,036,854,775,807'ye kadar artabildiğinin farkında mısınız?

[ID_CODE] [bigint] IDENTITY(1,1)

Google için bu veritabanını oluşturmadığınız sürece, int identity (1,1)2 Milyardan fazla limiti olan normal bir şey yeterli olmayacak mı?


int, SQL'de 4 bayttır, bu da -2,1 milyar ila + 2,1 milyar arasındadır.
datagod

@datagod, ha teşekkürler, çok sayıda hane yanlış saydım!
bu sistemde kimlik yok

Cevabınız için teşekkürler. Mı [ID_CODE]olarak, PRIMARY KEYben kullanım eğer en iyi seçenek, [CODE]kolon tabloda arama yapmak için? Teşekkürler.
VansFannel

Birisi DB'mdeki verileri / kullanıcıları tahmin etmek ve sahip olduğum her şeyi hasat etmek için "int" in ardışık doğasını kullanana kadar bu teknenin içindeydim. Bir daha asla. Halka açık DB'lerin bilgi almak için biraz daha zor olması gerekir.
DaBlue

3

Farkında değilse, nvarchar / varchar kullanırken geniş anahtar kullanma riskiniz dışında, doğası gereği / gözle görülür bir ceza olmamalıdır. Özellikle bileşik anahtarlarda birleştirmeye başlarsanız.

Ama (20) uzunluk örneğinde iyi olmalısın ve bu konuda fazla endişelenmem. Çünkü eğer CODE çoğunlukla verilerinizi nasıl sorgulayacağınızsa - kulağa kümelenmiş bir dizin çok mantıklı geliyor.

Ancak, bunu birincil anahtar mı yoksa yalnızca benzersiz (kümelenmiş) bir dizin olarak mı istediğinizi düşünmelisiniz. Kümelenmiş dizin ile birincil anahtar arasında (temel olarak birincil anahtar verilerinizi tanımlar, ancak dizin verileri nasıl sorguladığınızdır) arasında küçük bir fark vardır; CODE üzerinden benzersiz bir kümelenmiş dizin oluşturun. (dikkat: Kümelenmiş dizini kendiniz oluşturmadığınız sürece SQL Server Birincil Anahtarınızı otomatik olarak kümelenmiş bir dizine dönüştürür )

Ayrıca gerçekten ID_Code'a ihtiyacınız olup olmadığını şimdi benzersiz bir CODE'niz olduğunu düşünün.


2
Aslında NVARCHAR(20)olan 40 boyutunda (max) içinde bayt ve 's beri değişken uzunlukta sütun gerçekten kümelenmiş bir dizin için en iyi seçenek değildir. ID_CODEbir olmak burada çok daha iyi bir seçim BIGINT IDENTITYolurdu !
marc_s

40 bayt olduğunu biliyorum, ancak 900 baytın yakınında hiçbir yerde olmadığını görerek belirtmek için fazla bir neden yoktu. Ve esas olarak KOD'daki verileri sorgularsanız, korumak için gereksiz dizinlere sahip olmaktan kaçınmak daha iyi bir seçim olacaktır, çünkü yine de bir dizine ihtiyacınız olacak ve daha sonra kümelenmiş kıçından arama yapmanız gerekecek
Allan S. Hansen

Bahsetmeye değer - bahsetmeyi unuttuğum ve @marc_s'ın adreslediği yerde olduğundan şüphelendiğim, bu tür bir dizinin sıralı bir kimliğe göre daha büyük dizin parçalanmasına yol açabileceğidir, ancak yine de bu özel duruma dayalı olarak makul bir dizin olarak görüyorum sorgulama faktörü.
Allan S. Hansen
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.