Niedawno odziedziczyłem bazę danych SQL Server, która używa BINARY(16)
zamiast UNIQUEIDENTIFIER
przechowywać Guids. Robi to wszystko, w tym klucze podstawowe.
Czy powinienem się martwić?
sql-server
migration
uuid
Jonathan Allen
źródło
źródło
Odpowiedzi:
Jest tu kilka rzeczy, które są trochę niepokojące.
Po pierwsze: chociaż prawdą jest, że a
UNIQUEIDENTIFIER
(tj.Guid
) Jest 16-bajtową wartością binarną, prawdą jest również, że:INT
Mogą być przechowywaneBINARY(4)
,DATETIME
mogą być przechowywane wBINARY(8)
itp.), Stąd # 2 ↴sysname
Jako aliasNVARCHAR(128)
).Trzy różnice behawioralne, które mogę znaleźć to:
Porównywanie
UNIQUEIDENTIFIER
wartości w SQL Server, na lepsze lub na gorsze, w rzeczywistości nie odbywa się w ten sam sposób, co porównywanieBINARY(16)
wartości. Zgodnie ze stroną MSDN do porównywania wartości identyfikatora GUID i unikalnego identyfikatora podczas porównywaniaUNIQUEIDENTIFIER
wartości w programie SQL Server:Chociaż te wartości nie są często sortowane, istnieje niewielka różnica między tymi dwoma typami. Według strony MSDN dla unikalnego identyfikatora :
Biorąc pod uwagę, że istnieją różnice w sposobie, w jaki wartości GUID są obsługiwane między SQL Server i .NET (zauważono na stronie „Porównywanie wartości GUID i unikatowych identyfikatorów” powyżej), wyciągnięcie tych danych z SQL Server do kodu aplikacji może nie być właściwie obsługiwane w kod aplikacji, jeśli trzeba emulować zachowanie porównawcze programu SQL Server. To zachowanie można emulować, konwertując na a
SqlGuid
, ale czy programista wiedziałby o tym?Po drugie: w oparciu o następujące oświadczenie
Byłbym ogólnie zaniepokojony wydajnością systemu za pomocą GUID-ów jako PK zamiast kluczy alternatywnych wraz z używaniem
INT
lub nawetBIGINT
jako PK. I jeszcze bardziej zaniepokojony, jeśli te GUID PK są indeksami klastrowymi.AKTUALIZACJA
Poniższy komentarz, zamieszczony przez OP w odpowiedzi na @ Roba, budzi dodatkowe obawy:
Identyfikatory GUID mogą być przechowywane w 2 różnych formatach binarnych . Tak więc, nie mógłby być powodem do niepokoju w zależności od:
Problem z wygenerowaniem reprezentacji binarnej dotyczy uporządkowania bajtów pierwszych 3 z 4 „pól”. Jeśli klikniesz powyższy link do artykułu w Wikipedii, zobaczysz, że RFC 4122 określa użycie kodowania „Big Endian” dla wszystkich 4 pól, ale identyfikatory GUID firmy Microsoft określają użycie „Native” Endianness. Architektura Intela to Little Endian, stąd kolejność bajtów dla pierwszych 3 pól jest odwrócona od systemów zgodnych z RFC (podobnie jak identyfikatory GUID typu Microsoft generowane w systemach Big Endian). Pierwsze pole, „Dane 1”, ma 4 bajty. W jednym Endianness byłby reprezentowany jako (hipotetycznie)
0x01020304
. Ale w drugiej Endianness byłoby to0x04030201
. Więc jeśli bieżąca baza danych „BINARY(16)
ta reprezentacja binarna została wygenerowana w systemie zgodnym z RFC, a następnie konwersja danych znajdujących się obecnie wBINARY(16)
polu na innyUNIQUEIDENTIFIER
spowoduje, że GUID będzie inny niż pierwotnie utworzony. Nie stanowi to tak naprawdę problemu, JEŻELI wartości nigdy nie opuściły bazy danych, a wartości są zawsze porównywane tylko dla równości, a nie porządku.Problem z zamawianiem polega po prostu na tym, że po konwersji nie będą one w tej samej kolejności
UNIQUEIDENTIFIER
. Na szczęście, jeśli oryginalnym systemem naprawdę był MySQL, to w ogóle nigdy nie przeprowadzono porządkowania reprezentacji binarnej, ponieważ MySQL ma tylko ciąg znaków UUID .Niepokój związany z używaniem wartości ciągu poza bazą danych jest poważniejszy, jeśli reprezentacja binarna została wygenerowana poza systemem Windows / SQL Server. Ponieważ kolejność bajtów jest potencjalnie różna, ten sam identyfikator GUID w postaci ciągu spowodowałby 2 różne reprezentacje binarne, w zależności od tego, gdzie miała miejsce ta konwersja. Jeśli kod aplikacji lub klienci otrzymają identyfikator GUID w postaci ciągu jako
ABC
pochodzący z postaci binarnej,123
a reprezentacja binarna zostanie wygenerowana w systemie zgodnym z RFC, wówczas ta sama reprezentacja binarna (tj.123
) Przełoży się na postać ciągowąDEF
po przekonwertowaniu naUNIQUEIDENTIFIER
. Podobnie, oryginalna forma ciąguABC
przekształciłaby się w postać binarną456
po konwersji na aUNIQUEIDENTIFIER
.Jeśli więc identyfikatory GUID nigdy nie opuściły bazy danych, nie ma powodów do obaw poza zamówieniem. Lub, jeśli import z MySQL został dokonany przez konwersję postaci ciągu (tj.
FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40
), Może być w porządku. W przeciwnym razie, jeśli te identyfikatory GUID zostały podane klientom lub w kodzie aplikacji, możesz przetestować, aby przekonać się, w jaki sposób dokonują konwersji, uzyskując jeden i konwertując je,SELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');
i sprawdzając, czy znajdziesz oczekiwany rekord. Jeśli nie możesz dopasować rekordów, być może będziesz musiał zachować pola jakoBINARY(16)
.Najprawdopodobniej nie będzie problemu, ale wspominam o tym, ponieważ w odpowiednich warunkach może wystąpić problem.
A w jaki sposób wstawiane są nowe identyfikatory GUID? Wygenerowano w kodzie aplikacji?
AKTUALIZACJA 2
Jeśli poprzednie wyjaśnienie potencjalnego problemu związanego z importowaniem reprezentacji binarnych identyfikatorów GUID wygenerowanych w innym systemie było nieco (lub bardzo) mylące, mam nadzieję, że następujące wyjaśnienia będą nieco jaśniejsze:
W wynikach pokazanych powyżej wartości „String” i „Binary” pochodzą z tego samego identyfikatora GUID. Wartość pod wierszem „Binarna” jest taka sama jak linia „Binarna”, ale sformatowana w tym samym stylu co linia „Ciąg” (tzn. Usunięta „0x” i dodała cztery myślniki). Porównując pierwszą i trzecią wartość, nie są dokładnie takie same, ale są bardzo blisko: dwie skrajnie prawe dwie sekcje są identyczne, ale trzy skrajnie lewe nie są. Ale jeśli przyjrzysz się uważnie, zobaczysz, że są to te same bajty w każdej z trzech sekcji, tylko w innej kolejności. Łatwiej byłoby zobaczyć, czy pokazuję tylko te trzy pierwsze sekcje i numeruję bajty, więc łatwiej jest zobaczyć, jak różni się ich kolejność między dwiema reprezentacjami:
Łańcuch = 1 5F 2 ED 3 23 4 BE - 5 E5 6 2C - 7 40 8 EE
Binarny = 4 BE 3 23 2 ED 1 5F - 6 2C 5 E5 - 8 EE 7 40 (w systemie Windows / SQL Server)
Tak więc w każdej grupie kolejność bajtów jest odwrócona, ale tylko w systemie Windows, a także SQL Server. Jednak w systemie zgodnym z RFC reprezentacja binarna odzwierciedlałaby reprezentację żądła, ponieważ nie nastąpiłoby odwrócenie kolejności bajtów.
W jaki sposób dane zostały wprowadzone do SQL Server z MySQL? Oto kilka opcji:
Zwroty:
Zakładając, że był to prosty układ dwójkowy na dwójkowy (tj. Konwertuj nr 2 powyżej), wynikowy identyfikator GUID, jeśli zostanie przekonwertowany na rzeczywisty
UNIQUEIDENTIFIER
, będzie:Zwroty:
Co jest złe. I to pozostawia nam trzy pytania:
źródło
Zawsze możesz się martwić. ;)
System mógł zostać migrowany z innego systemu, który nie obsługuje unikalnego identyfikatora. Czy są jeszcze inne kompromisy, o których nie wiesz?
Projektant mógł nie wiedzieć o typie unikalnego identyfikatora. O jakich innych sprawach nie wiedzieli?
Technicznie jednak - nie powinno to stanowić większego problemu.
źródło