GUID'i, özellikle performansla ilgili birincil anahtar olarak kullanmak için en iyi uygulamalar nelerdir?


336

Hemen hemen tüm tablolarda GUID birincil anahtar olarak kullanan bir uygulama var ve birincil anahtar olarak GUID kullanırken performans ile ilgili sorunlar olduğunu okudum. Dürüst olmak gerekirse, herhangi bir sorun görmedim, ancak yeni bir uygulama başlatmak üzereyim ve yine de GUID'leri Birincil Anahtarlar olarak kullanmak istiyorum, ancak Kompozit Birincil Anahtar (GUID ve belki de başka bir alan) kullanmayı düşünüyordum .)

GUID kullanıyorum çünkü "üretim", "test" ve "dev" veritabanları gibi farklı ortamlara sahip olduğunuzda ve ayrıca veritabanları arasında geçiş verileri için kolay ve kolay yönetilebilirler.

Entity Framework 4.3 kullanacağım ve veritabanına eklemeden önce Guid'i uygulama koduna atamak istiyorum. (yani SQL Kılavuzu oluşturmak izin istemiyorum).

Bu yaklaşımla ilişkili varsayılan performans vuruşlarından kaçınmak için GUID tabanlı Birincil Anahtarlar oluşturmak için en iyi uygulama nedir?


20
Sorun söz konusu değil. PK'niz kümelenmişse, hemen hemen her ekin sayfa bölünmesine neden olma potansiyeli vardır. SQL Server'ın modern sürümlerinde bu, NEWSEQUENTIALID () ile "düzeltildi", ancak bu önceden hesaplayabilme avantajını kaybeder. Başka bir yerde GUID'leri okumanızı şiddetle tavsiye ederim, çünkü bu çok geniş bir soru ve muhtemelen saatlerce sürecek dini bir savaş isteyecektir ...
Aaron Bertrand

4
Ayrıca kelime eklemek istiyorum sunucu içinde belirsiz I Guid atamak istediğiniz sunucu tarafında (dont GUID oluşturmak için SQL izin vermek istiyorum) .
Erik Philips

Bu sorunun bu "sql-server-guid-sort-algorithm-why" ile benzerlikleri vardır stackoverflow.com/questions/7810602/…
Clinton Ward

Yanıtlar:


495

GUID'ler birincil anahtarınız için doğal bir seçim gibi görünebilir - ve gerçekten yapmanız gerekiyorsa, bunu tablonun PRIMARY KEY'i için kullanmayı iddia edebilirsiniz. Ne şiddetle tavsiye ediyorum yapmamaya olarak GUID sütun kullanmaktır kümeleme anahtarının özel olarak bunu değil söylemediğiniz sürece, SQL Server varsayılan olarak yapar.

Gerçekten iki konuyu birbirinden ayırmanız gerekiyor:

  1. Birincil anahtar mantıksal yapıdır - benzersiz ve güvenilir bir tablodaki her satır tanımlayan aday anahtarlarından biridir. Bu, herhangi bir şey olabilir - gerçekten INT, bir GUID, bir dize - senaryonuz için en anlamlı olanı seçin.

  2. kümeleme anahtar (sütun veya tablo üzerinde "kümelenmiş bir dizin" define sütunlar) - this is a fiziksel küçük, istikrarlı, sürekli artan veri türü en iyi yoldur, burada depolama ilgili bir şey, ve - INTveya BIGINTsenkronize eder varsayılan seçenek.

Varsayılan olarak, bir SQL Server tablosundaki birincil anahtar da kümeleme anahtarı olarak kullanılır - ancak bu şekilde olması gerekmez! Kişisel olarak önceki GUID tabanlı Birincil / Kümelenmiş Anahtarı iki ayrı anahtara ayırırken büyük performans artışları gördüm - GUID'deki birincil (mantıksal) anahtar ve ayrı bir INT IDENTITY(1,1)sütundaki kümeleme (sıralama) anahtarı .

As Kimberly Tripp indeksleme Kraliçesi - - ve diğerleri pek çok kez belirttiğimiz - Bir GUIDkümelenme anahtarının rastgelelik nedeniyle beri, bu kitlesel sayfa ve endeks parçalanma ve genellikle kötü performans sağlayacaktır, optimum olmasın.

Evet, biliyorum - newsequentialid()SQL Server 2005 ve üstü - ama bu gerçekten ve tamamen sıralı değildir ve bu nedenle aynı problemlerden muzdariptir GUID- sadece biraz daha az belirgin.

Sonra göz önünde bulundurulması gereken başka bir sorun var: bir tablodaki kümeleme anahtarı, tablonuzdaki kümelenmemiş her bir dizinin her girişine de eklenecektir - böylece gerçekten mümkün olduğunca küçük olduğundan emin olmak istersiniz. Tipik olarak, INTtabloların büyük çoğunluğu için 2+ milyar satırlık bir yeterli olmalıdır GUIDve kümeleme anahtarı olarak karşılaştırıldığında , diskte ve sunucu belleğinde yüzlerce megabayt depolama alanı kaydedebilirsiniz.

Hızlı hesaplama - kullanılarak INTvs GUIDİlk ve Kümelenme Anahtar olarak:

  • 1000.000 satır içeren Temel Tablo (3.8 MB ve 15.26 MB)
  • 6 kümelenmemiş dizin (22.89 MB ve 91.55 MB)

TOPLAM: 25 MB ve 106 MB - ve bu sadece tek bir masada!

Düşünce için biraz daha yiyecek - Kimberly Tripp tarafından mükemmel şeyler - okuyun, tekrar okuyun, sindirin! Gerçekten SQL Server indeksleme müjdesi.

PS: tabii ki, sadece birkaç yüz veya birkaç bin satırla uğraşıyorsanız - bu argümanların çoğunun gerçekten sizin üzerinde bir etkisi olmayacaktır. Ancak: Eğer onlarca veya yüzlerce satır binlerce içine almak ya da milyonlarca saymaya başla eğer - o zaman bu noktalar çok önemli ve anlamak çok önemli hale gelir.

Güncelleme: Eğer yapmak istiyorsanız PKGUIDbirincil anahtar olarak sütun (ancak kümeleme anahtarı) ve başka bir sütun MYINT( INT IDENTITYsizin kümeleme anahtar olarak) - kullanırız

CREATE TABLE dbo.MyTable
(PKGUID UNIQUEIDENTIFIER NOT NULL,
 MyINT INT IDENTITY(1,1) NOT NULL,
 .... add more columns as needed ...... )

ALTER TABLE dbo.MyTable
ADD CONSTRAINT PK_MyTable
PRIMARY KEY NONCLUSTERED (PKGUID)

CREATE UNIQUE CLUSTERED INDEX CIX_MyTable ON dbo.MyTable(MyINT)

Temelde: Sadece zorunda açıkça söylemek PRIMARY KEYo en o kısıtlamasını NONCLUSTERED(aksi takdirde, varsayılan olarak kümelenmiş endeksi olarak yarattı) - ve sonra olarak tanımladı ikinci indeks oluşturmakCLUSTERED

Bu işe yarar - ve performans için "yeniden tasarlanması" gereken bir sisteminiz varsa geçerli bir seçenektir. Yeni bir sistem için, sıfırdan başlarsanız ve bir çoğaltma senaryosunda değilseniz, o zaman her zaman ID INT IDENTITY(1,1)kümelenmiş birincil anahtarım olarak seçerim - her şeyden çok daha verimli!


2
Bu harika bir cevap, bahsettiğim bir şey, anahtar eklemeden önce anahtar üretebilmek için genellikle yararlıdır. "Newsequentialid ()" kullanmak kümelemeye yardımcı olabilir, ancak bu SQL'e ek bir gidiş-dönüş gerektirir. "Yedek anahtar" yaklaşımının bir diğer yararı da, istemci tarafında daha az dizin parçalanma kaygısı ile yeni kimlikler oluşturabilmenizdir.
Andrew Theken

2
Bunu okuduğum yol, hem kümelenmemiş bir uniqueidentifier sütunu hem de int kimlik sütunu olan FK'ların aynı zamanda uniqueidentifier olması mı? Bunu yaparsanız, kimlik sütununu doğrudan ne zaman kullanırsınız yoksa kullanmazsınız?
pinkfloydx33

2
Küçük bir soru, GUID artık birleştirmelerde veya int id'de kullanılmalı mı? İçgüdüm bana GUID'in kullanılması gerektiğini söylüyor, ancak int kimliğini kullanarak teknik bir sorun göremiyorum ...
Nicolas Belley

3
@marc_s ancak çoğaltma senaryosunda, int sütunu kimlikse, int sütunu aygıtlar arasında tekrarlanabileceğinden GUID kullanmamalıyız?
Nicolas Belley

6
@Kipei: ana konuları olan IF - o zaman evet, birincil anahtar olarak kullanabilirsiniz Böyle bir doğal değere sahip. AMA : DATETIMEörneğin 3.33ms doğruluğa sahip oldukları ve bu nedenle yinelemeler olabildiği için, örneğin gibi değerler bir kümeleme anahtarı için Faydalı DEĞİLDİR . Yani böyle bir durumda, hala * bir INT IDENTITYyerine ihtiyacınız var - bu nedenle, genellikle varsayılan olarak kullanıyorum, çünkü 20 yıllık tecrübemden sonra, gerçekten kullanışlı bir doğal anahtar neredeyse hiç yok ....
marc_s

51

2005'ten beri GUID'leri PKs olarak kullanıyorum. Bu dağıtılmış veritabanı dünyasında, dağıtılmış verileri birleştirmenin kesinlikle en iyi yoludur. Birleştirilmiş tablolarda eşleşen tüm ints endişesi olmadan birleştirme tablolarını ateşleyebilir ve unutabilirsiniz. GUID birleşimleri endişe duymadan kopyalanabilir.

Bu GUID'leri kullanmak için benim kurulum:

  1. PK = GUID. GUID'ler dizelere benzer şekilde dizine eklenir, bu nedenle yüksek satır tabloları (50 milyondan fazla kayıt) tablo bölümleme veya diğer performans tekniklerine ihtiyaç duyabilir. SQL Server son derece verimli hale geliyor, bu nedenle performans endişeleri giderek daha az uygulanabilir.

  2. PK Guid Kümelenmemiş dizinidir. NewSequentialID olmadığı sürece asla bir GUID dizinini kümelendirmeyin. Ancak o zaman bile, sunucunun yeniden başlatılması siparişte büyük kesintilere neden olacaktır.

  3. Her tabloya ClusterID Int ekleyin. Bu sizin tablonuzu sipariş eden KÜMELENMİŞ Endeksinizdir.

  4. ClusterID'lere (int) katılmak daha verimlidir, ancak 20-30 milyon kayıt tablosuyla çalışıyorum, bu nedenle GUID'lere katılmak performansı gözle etkilemez. Maksimum performans istiyorsanız, birincil anahtarınız olarak ClusterID kavramını kullanın ve ClusterID'de katılın.

İşte benim E-posta tablom ...

CREATE TABLE [Core].[Email] (
    [EmailID]      UNIQUEIDENTIFIER CONSTRAINT [DF_Email_EmailID] DEFAULT (newsequentialid()) NOT NULL,        
    [EmailAddress] NVARCHAR (50)    CONSTRAINT [DF_Email_EmailAddress] DEFAULT ('') NOT NULL,        
    [CreatedDate]  DATETIME         CONSTRAINT [DF_Email_CreatedDate] DEFAULT (getutcdate()) NOT NULL,      
    [ClusterID] INT NOT NULL IDENTITY,
    CONSTRAINT [PK_Email] PRIMARY KEY NonCLUSTERED ([EmailID] ASC)
);
GO

CREATE UNIQUE CLUSTERED INDEX [IX_Email_ClusterID] ON [Core].[Email] ([ClusterID])
GO

CREATE UNIQUE NONCLUSTERED INDEX [IX_Email_EmailAddress] ON [Core].[Email] ([EmailAddress] Asc)

PK_Email kısıtlamasını açıklayabilir misiniz? Neden ... Kümelenmemiş (ClusterID ASC) yerine ... Kümelenmemiş (EmailID ASC) var?
Phil

2
Emin ol. Dizinlerle devam eden iki temel şey: 1. ClusterID üzerinde kümelenmiş - Tablonuzu diskte sıralar (% 0 parçalanma). 2. EmailID'de Kümelenmemiş - GUID ID aramalarını hızlandırmak için EmailID alanını endeksler. Bir GUID alan araması string-ish davranır, böylece bir EmailID araması dizin olmadan yavaş olur.
Robert J. Good

@ RobertJ.Good Daha önce tartışılan bu yöntemi gördüm yani kümeye bir vekil int anahtar eklemek. Ama bir yığın kullanarak bir vekil anahtar kümelenmiş dizin sahip performans kazancı gösteren hiçbir yerde bulamıyorum. Kıyaslama verilerine bağlantınız var mı?
Dale K

1
Merhaba @DaleBurrell, kümelenmiş dizin tablo parçalanmasını önlemek içindir. Performans kazancı, tablonun doğal olarak diskte sıralı olarak artması ve düşük parçalanma ile olur.
Robert J. Good

@ RobertJ.Good Bu bir web uygulaması mı? URL / hrefs'de ne kullanıyorsunuz? guid veya int?
dariol

10

Şu anda EF Core ile bir web uygulaması geliştiriyorum ve işte kullandığım kalıp:

Tüm derslerim (tablolarım) ve int PK ve FK. Üzerinde kümelenmemiş bir dizin ile Guid (c # yapıcı tarafından oluşturulan) türü ile ek bir sütun var.

EF içindeki tüm tablo birleşimleri int anahtarlarıyla yönetilirken dışarıdan (kontrolörler) tüm erişim Rehberler ile yapılır.

Bu çözüm, URL'lerde int anahtarlarının gösterilmemesine izin verir, ancak modeli düzenli ve hızlı tutar.


Veri ek açıklamaları gibi pK tamsayısını kümelenmiş olarak yapılandırmak için yapmanız gereken herhangi bir şey var mı, yoksa yalnızca otomatik olarak yapılandırılmış mı?
Allen Wang

Guid one için mülkün adını ne kullanıyorsunuz?
Trong Phan

3

Birincil anahtar olarak GUID kullanırsanız ve kümelenmiş dizin oluşturursanız, bunun için varsayılan NEWSEQUENTIALID () değerini kullanmanızı öneririm


neden bunu yapasın ki?
genuinefafa

3

Bu bağlantı, yapabileceğimden daha iyi olduğunu ve karar vermeme yardımcı olduğunu söylüyor. Ben belirli bir gerek yok sürece ben genellikle bir birincil anahtar olarak bir int tercih ve ben de bazı özel bir neden olmadığı sürece ben de SQL Server otomatik olarak oluşturmak / bu alanı korumak izin. Gerçekte, performans kaygılarının uygulamanıza göre belirlenmesi gerekir. Burada beklenen db boyutu, uygun indeksleme, verimli sorgulama ve daha fazlası dahil olmak üzere burada birçok faktör vardır. İnsanlar katılmamalarına rağmen, birçok senaryoda her iki seçenekle de bir fark görmeyeceğinizi düşünüyorum ve uygulamanız için neyin daha uygun olduğunu ve daha kolay, daha hızlı ve daha etkili bir şekilde geliştirmenize izin veren şeyleri seçmelisiniz (Uygulamayı tamamlamazsanız) gerisi ne fark eder :).

https://web.archive.org/web/20120812080710/http://databases.aspfaq.com/database/what-should-i-choose-for-my-primary-key.html

PS: Neden Kompozit PK kullanacağınızdan veya bunun size sağlayacağına inandığınızdan emin değilim.


Tamamen katılıyorum!! Ancak bu, PK olarak bir GUID'im veya GUID'li bir Kompozit PK'm varsa ve diğer alanların aynı olması gerektiği anlamına gelir?
VAAA

1
PK (dizin) iki sütundan oluşur, ancak bunu yapmak için işe özgü bir nedeniniz yoksa, gereksiz görünüyor.
Matt

1
BTW bu soru en polarize ve tartışılan sorulardan biridir ve bu nedenle% 100 rahat hissedeceğiniz için bir cevap almak son derece zordur. Her iki yöntem de takaslar ile geliyor, çok iyi şanslar :)
Matt


0

Sıralı kimliklere sahip olmak, bir bilgisayar korsanının veya veri madencisinin sitenizi ve verilerinizi tehlikeye atmasını çok daha kolay hale getirir. Bir web sitesi için bir PK seçerken bunu aklınızda bulundurun.


Bu iddiayı desteklemek için herhangi bir mantık veya kanıt sağlayabilir misiniz? Sıralı bir kimliğin güvenliği nasıl tehlikeye atabileceğini görmek için mücadele ediyorum.
jonaglon

Elbette, kimlik numaralarının tam sayı olduğunu biliyorsanız, bir DB'deki sıralı kayıtları tahmin edebilirsiniz. Tek bir öğeyi sorgularsanız, bir sonraki öğenin pk + 1 olduğunu söyleyebilirsiniz. Rastgele GUIDS'iniz varsa, bir kalıp izlemez. Daha önce sorguladığınız kayıtlardan başka kayıtları sorgulamak neredeyse imkansızdır (Ve PK'yi tanıyın).
DaBlue

1
Bir bilgisayar korsanı zaten tehlikeye atılmış veritabanınızı sorgulayabilir, sıralı kimliğin durumu nasıl kötüleştirdiğini göremiyorum.
jonaglon

1
Bir kullanıcı 1012'yi başka bir numara için kapatabilir ve yapmaması gereken verileri görebilirse, çok ciddi bir güvenlik sorunu vardır, bu sorun birincil anahtar seçiminden kaynaklanmaz, ancak daha da artar. Demek istediğim, açıkladığınız için teşekkür ederim.
jonaglon

2
Web sayfasında, tablonun PK'si olmayan bir kaydı bulmak için bir GUID kullanabilirsiniz. Bir web sitesinde sorgu parametresi kullanmak, DB şemanızı nasıl yapılandırdığınızı tanımlamamalıdır. PK'nın UI veya arka uç sistemindeki giriş ve parametrelerle ilgisi yoktur.
Panos Roditakis
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.