Son zamanlarda Guids saklamak BINARY(16)
yerine kullanılan bir SQL Server veritabanı UNIQUEIDENTIFIER
devralmış. Bunu birincil anahtarlar dahil her şey için yapar.
Endişelenmeli miyim?
Son zamanlarda Guids saklamak BINARY(16)
yerine kullanılan bir SQL Server veritabanı UNIQUEIDENTIFIER
devralmış. Bunu birincil anahtarlar dahil her şey için yapar.
Endişelenmeli miyim?
Yanıtlar:
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:
INT
saklanabilir olabilir BINARY(4)
, DATETIME
saklanabilir BINARY(8)
dolayısıyla 2. vs.) elde ↴sysname
bir takma ad olarak NVARCHAR(128)
).Bulabildiğim üç davranış farklılığı:
Karşılaştırma UNIQUEIDENTIFIER
iyi 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 INT
ve hatta BIGINT
PK olarak kullanarak sistem performansından endişe ediyorum . Ve bu GUID PK'lerin Kümelenmiş Endeksler olup olmadığı daha da endişeli.
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:
İ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 ABC
ikili 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, ABC
a'ya dönüştürüldüğünde ikili biçimine 456
dö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?
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:
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ı.