Di recente ho ereditato un database SQL Server che utilizza BINARY(16)
invece di UNIQUEIDENTIFIER
archiviare le guide. Lo fa per tutto, comprese le chiavi primarie.
Dovrei essere preoccupato?
Di recente ho ereditato un database SQL Server che utilizza BINARY(16)
invece di UNIQUEIDENTIFIER
archiviare le guide. Lo fa per tutto, comprese le chiavi primarie.
Dovrei essere preoccupato?
Risposte:
Dovrei essere preoccupato?
Bene, ci sono un paio di cose qui che sono un po 'preoccupanti.
Primo: mentre è vero che un UNIQUEIDENTIFIER
(cioè Guid
) è un valore binario a 16 byte, è anche vero che:
INT
potrebbe essere immagazzinate nella BINARY(4)
, DATETIME
possono essere memorizzati in BINARY(8)
, ecc), quindi 2 # ↴sysname
Come alias per NVARCHAR(128)
).Le tre differenze comportamentali che posso trovare sono:
Il confronto dei UNIQUEIDENTIFIER
valori in SQL Server, nel bene e nel male, non è effettivamente fatto allo stesso modo del confronto dei BINARY(16)
valori. Secondo la pagina MSDN per confrontare i valori GUID e uniqueidentifier , quando si confrontano i UNIQUEIDENTIFIER
valori in SQL Server:
gli ultimi sei byte di un valore sono più significativi
Sebbene questi valori non vengano ordinati di frequente, esiste una leggera differenza tra questi due tipi. Secondo la pagina MSDN per uniqueidentifier :
l'ordinamento non viene implementato confrontando i modelli di bit dei due valori.
Dato che esistono differenze nel modo in cui i valori GUID vengono gestiti tra SQL Server e .NET (indicato nella pagina "Confronto tra valori GUID e uniqueidentifier" collegati sopra), l'estrazione di questi dati da SQL Server nel codice dell'app potrebbe non essere gestita correttamente in il codice dell'app se è necessario emulare il comportamento di confronto di SQL Server. Tale comportamento può essere emulato convertendosi in a SqlGuid
, ma uno sviluppatore saprebbe farlo?
Secondo: basato sulla seguente dichiarazione
Lo fa per tutto, comprese le chiavi primarie.
Sarei preoccupato in generale per le prestazioni del sistema usando GUID come PK anziché come chiavi alternative insieme all'uso INT
o anche BIGINT
come PK. E ancora più preoccupato se questi GUK PK sono gli indici cluster.
Il seguente commento, fatto dall'OP sulla risposta di @ Rob, solleva un'ulteriore preoccupazione:
è stato migrato da penso a MySQL
I GUID possono essere memorizzati in 2 diversi formati binari . Quindi, potrebbero esserci motivi di preoccupazione a seconda di:
Il problema con cui è stata generata la rappresentazione binaria ha a che fare con l'ordinamento dei byte dei primi 3 dei 4 "campi". Se segui il link sopra all'articolo di Wikipedia, vedrai che RFC 4122 specifica di utilizzare la codifica "Big Endian" per tutti e 4 i campi, ma i GUID Microsoft specificano l'utilizzo di Endianness "nativo". Bene, l'architettura Intel è Little Endian, quindi l'ordine dei byte per i primi 3 campi è invertito dai sistemi che seguono l'RFC (così come i GUID in stile Microsoft generati sui sistemi Big Endian). Il primo campo, "Dati 1", è di 4 byte. In un Endianness sarebbe rappresentato come (ipoteticamente) 0x01020304
. Ma nell'altro Endianness sarebbe 0x04030201
. Quindi se il database corrente "BINARY(16)
tale rappresentazione binaria è stata generata su un sistema che segue RFC, quindi la conversione dei dati attualmente presenti nel BINARY(16)
campo in un UNIQUEIDENTIFIER
risultato risulterà in un GUID diverso da quello originariamente creato. Ciò non rappresenta un problema SE i valori non hanno mai lasciato il database e i valori vengono sempre e solo confrontati per uguaglianza e non ordinamento.
La preoccupazione per l'ordinamento è semplicemente che non saranno nello stesso ordine dopo la conversione in UNIQUEIDENTIFIER
. Fortunatamente, se il sistema originale era davvero MySQL, l'ordinamento non è mai stato fatto sulla rappresentazione binaria in primo luogo poiché MySQL ha solo una rappresentazione in stringa di UUID .
La preoccupazione per i valori di stringa utilizzati all'esterno del database è ancora più grave se la rappresentazione binaria è stata generata al di fuori di Windows / SQL Server. Poiché l'ordinamento dei byte è potenzialmente diverso, lo stesso GUID in forma di stringa comporterebbe 2 diverse rappresentazioni binarie, a seconda del luogo in cui è avvenuta la conversione. Se al codice dell'app o ai clienti fosse assegnato un GUID in forma di stringa come ABC
proveniente da una forma binaria di 123
e la rappresentazione binaria fosse generata su un sistema che segue RFC, quella stessa rappresentazione binaria (cioè 123
) si tradurrebbe in una forma stringa di DEF
quando convertita in a UNIQUEIDENTIFIER
. Allo stesso modo, la forma stringa originale di ABC
verrebbe convertita in una forma binaria di 456
quando convertita in a UNIQUEIDENTIFIER
.
Quindi, se i GUID non hanno mai lasciato il database, non c'è molto di cui preoccuparsi al di fuori dell'ordine. Oppure, se l'importazione da MySQL è stata eseguita convertendo il modulo stringa (cioè FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40
), potrebbe essere ok. Altrimenti, se quei GUID sono stati dati ai clienti o nel codice dell'app, puoi testare per vedere come si convertono ottenendone uno e convertendolo tramite SELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');
e vedi se trovi il record previsto. Se non riesci ad abbinare i record, potresti dover mantenere i campi come BINARY(16)
.
Con ogni probabilità non ci sarà un problema, ma lo sto menzionando perché nelle giuste condizioni potrebbe esserci un problema.
E come vengono comunque inseriti i nuovi GUID? Generato nel codice dell'app?
Se la precedente spiegazione del potenziale problema relativo all'importazione di rappresentazioni binarie di GUID generati su un altro sistema era un po '(o molto) confusa, si spera che quanto segue sarà un po' più chiaro:
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
Nell'output mostrato sopra, i valori "String" e "Binary" provengono dallo stesso GUID. Il valore sotto la riga "Binary" ha lo stesso valore della riga "Binary", ma formattato nello stesso stile della riga "String" (cioè rimosso "0x" e aggiunto i quattro trattini). Confrontando il primo e il terzo valore, non sono esattamente gli stessi, ma sono molto vicini: le due sezioni più a destra sono identiche, ma le tre sezioni più a sinistra non lo sono. Ma se guardi da vicino, puoi vedere che sono gli stessi byte in ciascuna delle tre sezioni, solo in un ordine diverso. Potrebbe essere più facile vedere se mostro solo quelle prime tre sezioni e numerare i byte, quindi è più facile vedere come il loro ordine differisce tra le due rappresentazioni:
Stringa = 1 5F 2 ED 3 23 4 BE - 5 E5 6 2C - 7 40 8 EE
Binary = 4 BE 3 23 2 ED 1 5F - 6 2C 5 E5 - 8 EE 7 40 (in Windows / SQL Server)
Quindi all'interno di ogni raggruppamento, l'ordinamento dei byte è invertito, ma solo all'interno di Windows e anche di SQL Server. Tuttavia, su un sistema che aderisce alla RFC, la rappresentazione binaria rispecchierebbe la rappresentazione pungente perché non ci sarebbe alcuna inversione dell'ordine dei byte.
Come sono stati trasferiti i dati in SQL Server da MySQL? Ecco alcune scelte:
SELECT CONVERT(BINARY(16), '5FED23BE-E52C-40EE-8F45-49664C9472FD'),
CONVERT(BINARY(16), 0x5FED23BEE52C40EE8F4549664C9472FD),
CONVERT(BINARY(16), CONVERT(UNIQUEIDENTIFIER, '5FED23BE-E52C-40EE-8F45-49664C9472FD'));
Ritorna:
0x35464544323342452D453532432D3430
0x5FED23BEE52C40EE8F4549664C9472FD
0xBE23ED5F2CE5EE408F4549664C9472FD
Supponendo che fosse direttamente binario in binario (cioè Converti n. 2 sopra), il GUID risultante, se convertito in un effettivo UNIQUEIDENTIFIER
, sarebbe:
SELECT CONVERT(UNIQUEIDENTIFIER, 0x5FED23BEE52C40EE8F4549664C9472FD);
Ritorna:
BE23ED5F-2CE5-EE40-8F45-49664C9472FD
Che è sbagliato E questo ci lascia con tre domande:
Puoi sempre preoccuparti. ;)
Il sistema potrebbe essere stato migrato da qualche altro sistema che non supporta IDidentificatore univoco. Ci sono altri compromessi che non conosci?
Il progettista potrebbe non essere a conoscenza del tipo di identificativo univoco. Di quali altre cose non sapevano?
Tecnicamente però - non dovrebbe essere una delle maggiori preoccupazioni.