UNIQUEIDENTIFIER yerine BINARY (16) kullanmanın cezası var mı?


19

Son zamanlarda Guids saklamak BINARY(16)yerine kullanılan bir SQL Server veritabanı UNIQUEIDENTIFIERdevralmış. Bunu birincil anahtarlar dahil her şey için yapar.

Endişelenmeli miyim?


İkili (16) sürekli olarak kullanıyor mu? Değişkenler ve parametreler dahil mi? Değilse, örtük kastların etkilerini göz önünde bulundurmanız gerekir.
Martin Smith

Evet, çok şükür ki örtük kastlarla uğraşmak zorunda değilim.
Jonathan Allen

Yanıtlar:


21

Endişelenmeli miyim?

Burada biraz endişe duyan birkaç şey var.

Birincisi: a'nın UNIQUEIDENTIFIER(yani Guid) 16 baytlık bir ikili değer olduğu doğru olsa da:

  1. Tüm veriler (örneğin ikili biçimde saklanabilir INTsaklanabilir olabilir BINARY(4), DATETIMEsaklanabilir BINARY(8)dolayısıyla 2. vs.) elde ↴
  2. Muhtemelen GUID'ler için sadece kolaylık dışında ayrı bir veri tipine sahip olmanın bir nedeni vardır (örneğin sysnamebir takma ad olarak NVARCHAR(128)).

Bulabildiğim üç davranış farklılığı:

  • Karşılaştırma UNIQUEIDENTIFIERiyi ya da kötü, SQL Server değerleri, aslında karşılaştırarak aynı şekilde yapılmaz BINARY(16)değerleri. SQL Server'daki değerleri karşılaştırırken, GUID ve uniqueidentifier Değerlerini Karşılaştırma için MSDN sayfasına göre UNIQUEIDENTIFIER:

    bir değerin son altı baytı en önemlisidir

  • Bu değerler sık ​​sıralanmasa da, bu iki tür arasında küçük bir fark vardır. Uniqueidentifier için MSDN sayfasına göre :

    iki değerin bit kalıpları karşılaştırılarak sıralama uygulanmaz.

  • GUID değerlerinin SQL Server ve .NET arasında nasıl işlendiği konusunda farklılıklar olduğu göz önüne alındığında (yukarıda bağlanan "GUID ve benzersiz tanımlayıcı Değerlerini Karşılaştırma" sayfasında not edilmiştir), bu verilerin SQL Server'dan uygulama koduna çekilmesi, SQL Server karşılaştırma davranışını taklit etmek gerekiyorsa uygulama kodu. Bu davranış, a'ya dönüştürülerek taklit edilebilir SqlGuid, ancak bir geliştirici bunu yapmayı bilir mi?

İkincisi: aşağıdaki ifadeye dayanarak

Bunu birincil anahtarlar dahil her şey için yapar.

Genel olarak GUID'leri alternatif anahtarlar yerine PK'lar olarak INTve hatta BIGINTPK olarak kullanarak sistem performansından endişe ediyorum . Ve bu GUID PK'lerin Kümelenmiş Endeksler olup olmadığı daha da endişeli.

GÜNCELLEME

OP'nin @ Rob'un cevabı üzerine yaptığı aşağıdaki yorum ek bir endişe getiriyor:

bence MySQL'den taşındı

GUID'ler 2 farklı ikili biçimde saklanabilir . Yani, orada olabilir endişe bağlı için neden:

  1. ikili gösterimin hangi sistemde oluşturulduğu ve
  2. dize değerleri, uygulama kodu gibi orijinal sistemin dışında kullanılmışsa veya içe aktarma dosyalarında kullanılmak üzere istemcilere verilmişse vb.

İkili gösterimin oluşturulduğu sorun, 4 "alanın" ilk 3'ünün bayt sıralamasıyla ilgilidir. Yukarıdaki Wikipedia makalesine giden bağlantıyı izlerseniz, RFC 4122'nin 4 alanın tümü için "Big Endian" kodlamasını kullanmayı belirttiğini, ancak Microsoft GUID'lerinin "Native" Endianness kullanarak belirttiğini göreceksiniz. Intel mimarisi Little Endian, bu nedenle ilk 3 alan için bayt sırası RFC'yi (Big Endian sistemlerinde üretilen Microsoft tarzı GUID'leri) takip eden sistemlerden tersine çevrildi. İlk alan "Veri 1" 4 bayttır. Bir Endianitede (varsayımsal olarak) temsil edilir 0x01020304. Ama diğer Endianizm'de böyle olurdu 0x04030201. Yani şu anki veritabanı 'BINARY(16)bu ikili gösterim, RFC'yi izleyen bir sistemde oluşturulduktan sonra, o anda BINARY(16)sahada olan verilerin bir dönüştürülmesine dönüştürülüp UNIQUEIDENTIFIER, orijinal olarak oluşturulandan farklı bir GUID değeri oluşturulur. Bu gerçekten bir sorun teşkil etmez IF değerleri veritabanına sol asla ve değerler sadece hiç sipariş eşitlik için değil karşılaştırılır.

Sipariş verme konusundaki kaygı basitçe, dönüşümden sonra aynı sırada olmayacaklarıdır UNIQUEIDENTIFIER. Neyse ki, eğer orijinal sistem gerçekten MySQL ise, MySQL sadece UUID'nin dize olarak temsil edildiği için sipariş asla ilk etapta ikili temsilde yapılmadı .

Veritabanı dışında kullanılan dize değerleriyle ilgili endişe, ikili gösterim Windows / SQL Server dışında oluşturulduysa yine daha ciddidir. Bayt sıralaması potansiyel olarak farklı olduğundan, dize biçimindeki aynı GUID, bu dönüşümün gerçekleştiği yere bağlı olarak 2 farklı ikili sunumla sonuçlanır. Uygulama kodu veya müşterilere , RFC'yi izleyen bir sistemde ABCikili biçimde geldiği gibi dize biçiminde bir GUID verildiyse 123 ve ikili gösterim, RFC'yi izleyen bir sistemde oluşturulduysa, aynı ikili gösterim (yani 123) DEF, a UNIQUEIDENTIFIER. Benzer şekilde, orijinal dize biçimi, ABCa'ya dönüştürüldüğünde ikili biçimine 456dönüşür UNIQUEIDENTIFIER.

Dolayısıyla, GUID'ler veritabanından hiç ayrılmazsa, siparişin dışında endişelenecek çok şey yoktur. Veya, MySQL'den içe aktarma dize formunu (yani FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40) dönüştürerek yapıldıysa, sorun olmayabilir. Ayrıca, bu GUID'ler müşterilere veya uygulama kodunda verildiyse, bir tane alıp dönüştürerek nasıl dönüştüklerini SELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');ve beklenen kaydı bulup bulmadığınızı test edebilirsiniz . Kayıtları eşleştiremiyorsanız alanları olduğu gibi tutmanız gerekebilir BINARY(16).

Herhalde bir sorun olmayacak, ama bundan bahsediyorum çünkü doğru koşullar altında bir sorun olabilir.

Yeni GUID'ler nasıl eklenir? Uygulama kodunda mı oluşturuldunuz?

GÜNCELLEME 2

Başka bir sistemde oluşturulan GUID'in ikili temsillerini içe aktarmayla ilgili potansiyel sorunun önceki açıklaması biraz kafa karıştırıcıysa, umarım aşağıdakiler biraz daha açık olacaktır:

DECLARE @GUID UNIQUEIDENTIFIER = NEWID();
SELECT @GUID AS [String], CONVERT(BINARY(16), @GUID) AS [Binary];
-- String = 5FED23BE-E52C-40EE-8F45-49664C9472FD
-- Binary = 0xBE23ED5F2CE5EE408F4549664C9472FD
--          BE23ED5F-2CE5-EE40-8F45-49664C9472FD

Yukarıda gösterilen çıktıda, "String" ve "Binary" değerleri aynı GUID'den alınmıştır. "İkili" satırının altındaki değer "İkili" satır ile aynıdır, ancak "String" satırıyla aynı stilde biçimlendirilmiştir (yani "0x" kaldırılmıştır ve dört tireler eklenmiştir). Birinci ve üçüncü değerleri karşılaştırdıklarında, tam olarak aynı değildirler , ancak çok yakındırlar: en sağdaki iki bölüm aynıdır, ancak en soldaki üç bölüm aynı değildir. Ancak yakından bakarsanız, üç bölümün her birinde aynı bayt olduğunu, sadece farklı bir sırayla görebilirsiniz. Yalnızca ilk üç bölümü gösterip göstermediğimi görmek ve baytları numaralandırmak isteyip istemediğimi görmek daha kolay olabilir, böylece sıralarının iki gösterim arasında nasıl farklı olduğunu görmek daha kolaydır:

Dize = 1 5F 2 ED 3 23 4 BE - 5 E5 6 2C - 7 40 8 EE
İkili = 4 BE 3 23 2 ED 1 5F - 6 2C 5 E5 - 8 EE 7 40 (Windows / SQL Server'da)

Bu nedenle, her gruplandırmada, baytların sırası tersine çevrilir, ancak yalnızca Windows ve SQL Server'da tersine çevrilir. Bununla birlikte, RFC'ye bağlı bir sistemde, ikili gösterim, bayt sırasının tersine çevrilmemesi nedeniyle sokma temsilini yansıtacaktır.

Veriler MySQL'den SQL Server'a nasıl getirildi? İşte birkaç seçenek:

SELECT CONVERT(BINARY(16), '5FED23BE-E52C-40EE-8F45-49664C9472FD'),
       CONVERT(BINARY(16), 0x5FED23BEE52C40EE8F4549664C9472FD),
    CONVERT(BINARY(16), CONVERT(UNIQUEIDENTIFIER, '5FED23BE-E52C-40EE-8F45-49664C9472FD'));

İadeler:

0x35464544323342452D453532432D3430  
0x5FED23BEE52C40EE8F4549664C9472FD  
0xBE23ED5F2CE5EE408F4549664C9472FD

Düz ikiliden ikiliye (yani yukarıdaki # 2'yi Dönüştür) olduğu varsayılarak, gerçek olana dönüştürüldüğünde elde edilen GUID UNIQUEIDENTIFIERşöyle olur:

SELECT CONVERT(UNIQUEIDENTIFIER, 0x5FED23BEE52C40EE8F4549664C9472FD);

İadeler:

BE23ED5F-2CE5-EE40-8F45-49664C9472FD

Hangisi yanlış. Bu da bize üç soru bırakıyor:

  1. Veriler SQL Server'a nasıl aktarıldı?
  2. Uygulama kodu hangi dilde yazılıyor?
  3. Uygulama kodu hangi platformda çalışıyor?

Ben veritabanında görmüyorum gibi GUIDs, uygulamada oluşturulan varsayalım.
Jonathan Allen

Bayt sıralamasıyla ilgili açıklamayı tamamen takip ettiğimi söyleyemem, ama bu beni endeksleme hakkında düşündürüyor. Benzersiz tanımlayıcının, ikili dosyadan daha fazla veya daha az dizin parçalanmasına neden olması olası mıdır?
Jonathan Allen

2
@JonathanAllen Umarım daha iyi açıklamak için başka bir GÜNCELLEME bölümü ekledim. Ve hayır, indeksleme aralarında farklı olmamalı.
Solomon Rutzky

"Neyse ki", SQL Server, Varyant 1 ve Varyant 2 arasındaki sıralamayı değiştirmez - 'disk' farklı bir şekilde diskte saklansa bile, aynı kafa karıştırıcı sipariş sürekli olarak aynıdır.
user2864740

5

Her zaman endişelenebilirsiniz. ;)

Sistem, benzersiz tanımlayıcıyı desteklemeyen başka bir sistemden geçirilmiş olabilir. Bilmediğin başka tavizler var mı?

Tasarımcı benzersiz tanımlayıcı türünü bilmiyor olabilir. Başka ne bilmiyorlardı?

Teknik olarak - büyük bir endişe olmamalı.


Evet, sanırım MySQL'den taşındı. Ve evet, bakmak için çok ... ilginç şeyler var.
Jonathan Allen
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.