Recentemente, herdei um banco de dados do SQL Server que usa BINARY(16)
em vez de UNIQUEIDENTIFIER
armazenar Guids. Ele faz isso para tudo, incluindo chaves primárias.
Devo me preocupar?
Recentemente, herdei um banco de dados do SQL Server que usa BINARY(16)
em vez de UNIQUEIDENTIFIER
armazenar Guids. Ele faz isso para tudo, incluindo chaves primárias.
Devo me preocupar?
Bem, há algumas coisas aqui que são um pouco preocupantes.
Primeiro: embora seja verdade que a
UNIQUEIDENTIFIER
(ieGuid
) é um valor binário de 16 bytes, também é verdade que:INT
podem ser armazenados emBINARY(4)
,DATETIME
podem ser armazenados emBINARY(8)
, etc.), portanto #2 ↴sysname
, como um alias paraNVARCHAR(128)
).As três diferenças comportamentais que posso encontrar são:
A comparação
UNIQUEIDENTIFIER
de valores no SQL Server, para o bem ou para o mal, não é feita da mesma forma que a comparação deBINARY(16)
valores. De acordo com a página do MSDN para comparar valores GUID e uniqueidentifier , ao compararUNIQUEIDENTIFIER
valores no SQL Server:Embora esses valores não sejam classificados com frequência, há uma pequena diferença entre esses dois tipos. De acordo com a página do MSDN para identificador único :
Dado que há diferenças em como os valores GUID são tratados entre o SQL Server e o .NET (observado na página "Comparando GUID e valores de identificador exclusivo" vinculado acima), extrair esses dados do SQL Server para o código do aplicativo pode não ser tratado adequadamente em o código do aplicativo se precisar emular o comportamento de comparação do SQL Server. Esse comportamento pode ser emulado convertendo-se em um
SqlGuid
, mas um desenvolvedor saberia fazer isso?Segundo: com base na seguinte declaração
Eu ficaria preocupado em geral com o desempenho do sistema usando GUIDs como PKs em vez de chaves alternativas junto com o uso de um
INT
ou mesmoBIGINT
como o PK. E ainda mais preocupado se esses GUID PKs forem os índices clusterizados.ATUALIZAR
O seguinte comentário, feito pelo OP na resposta de @Rob, traz uma preocupação adicional:
GUIDs podem ser armazenados em 2 formatos binários diferentes . Portanto, pode haver motivo de preocupação dependendo de:
O problema de onde a representação binária foi gerada tem a ver com a ordem de bytes dos primeiros 3 dos 4 "campos". Se você seguir o link acima para o artigo da Wikipedia, verá que RFC 4122 especifica o uso da codificação "Big Endian" para todos os 4 campos, mas os GUIDs da Microsoft especificam o uso de Endianness "Nativo". Bem, a arquitetura Intel é Little Endian, portanto, a ordem de bytes para os primeiros 3 campos é invertida dos sistemas que seguem o RFC (bem como GUIDs estilo Microsoft gerados em sistemas Big Endian). O primeiro campo, "Data 1", tem 4 bytes. Em um Endianness seria representado como (hipoteticamente)
0x01020304
. Mas no outro Endianness seria0x04030201
. Portanto, se o banco de dados atual'BINARY(16)
que a representação binária foi gerada em um sistema seguindo o RFC, a conversão dos dados atualmente noBINARY(16)
campo em umUNIQUEIDENTIFIER
resultará em um GUID diferente do que foi originalmente criado. Isso realmente não representa um problema SE os valores nunca saírem do banco de dados e os valores forem comparados apenas por igualdade e não por ordem.A preocupação com a ordenação é simplesmente que eles não estarão na mesma ordem após a conversão para
UNIQUEIDENTIFIER
. Felizmente, se o sistema original realmente era o MySQL, a ordem nunca foi feita na representação binária em primeiro lugar, pois o MySQL só tem uma representação de string de UUID .A preocupação com os valores de string sendo usados fora do banco de dados é mais séria, novamente, se a representação binária foi gerada fora do Windows/SQL Server. Como a ordem de bytes é potencialmente diferente, o mesmo GUID na forma de string resultaria em 2 representações binárias diferentes, dependendo de onde ocorreu a conversão. Se o código do aplicativo ou os clientes recebessem um GUID em forma de string como
ABC
proveniente de uma forma binária de123
e a representação binária fosse gerada em um sistema seguindo o RFC, essa mesma representação binária (ou seja123
, ) seria convertida em uma forma de string deDEF
quando convertida em aUNIQUEIDENTIFIER
. Da mesma forma, a forma de string original deABC
seria convertida em uma forma binária de456
quando convertida emUNIQUEIDENTIFIER
.Portanto, se os GUIDs nunca deixaram o banco de dados, não há muito com o que se preocupar fora do pedido. Ou, se a importação do MySQL foi feita convertendo o formato de string (ou seja
FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40
), pode estar tudo bem. Caso contrário, se esses GUIDs foram fornecidos aos clientes ou no código do aplicativo, você pode testar para ver como eles convertem obtendo um e convertendo por meioSELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');
e ver se encontra o registro esperado. Se você não puder corresponder aos registros, talvez seja necessário manter os campos comoBINARY(16)
.Com toda a probabilidade, não haverá um problema, mas estou mencionando isso porque, nas condições certas, pode haver um problema.
E como os novos GUIDs são inseridos? Gerado no código do app?
ATUALIZAÇÃO 2
Se a explicação anterior do possível problema relacionado à importação de representações binárias de GUID geradas em outro sistema foi um pouco (ou muito) confusa, esperamos que o seguinte seja um pouco mais claro:
Na saída mostrada acima, os valores "String" e "Binary" são do mesmo GUID. O valor abaixo da linha "Binary" é o mesmo valor da linha "Binary", mas formatado no mesmo estilo da linha "String" (ou seja, removeu "0x" e adicionou os quatro traços). Comparando o primeiro e o terceiro valores, eles não são exatamente iguais, mas são muito próximos: as duas seções mais à direita são idênticas, mas as três seções mais à esquerda não. Mas se você olhar de perto, verá que são os mesmos bytes em cada uma das três seções, apenas em uma ordem diferente. Pode ser mais fácil ver se eu mostrar apenas as três primeiras seções e numerar os bytes para que seja mais fácil ver como sua ordem difere entre as duas representações:
String = 1 5F 2 ED 3 23 4 BE – 5 E5 6 2C – 7 40 8 EE
Binário = 4 BE 3 23 2 ED 1 5F – 6 2C 5 E5 – 8 EE 7 40 (em Windows / SQL Server)
Assim, dentro de cada agrupamento, a ordem dos bytes é invertida, mas apenas no Windows e também no SQL Server. No entanto, em um sistema que adere ao RFC, a representação binária espelharia a representação sting porque não haveria nenhuma reversão da ordem dos bytes.
Como os dados foram trazidos do MySQL para o SQL Server? Aqui estão algumas opções:
Retorna:
Supondo que fosse binário direto para binário (ou seja, Converter # 2 acima), então o GUID resultante, se convertido para um real
UNIQUEIDENTIFIER
, seria:Retorna:
O que está errado. E isso nos deixa com três perguntas:
Você sempre pode se preocupar. ;)
O sistema pode ter sido migrado de algum outro sistema que não oferece suporte ao identificador exclusivo. Existem outros compromissos que você não conhece?
O designer pode não saber sobre o tipo de identificador único. Que outras coisas eles não sabiam?
Tecnicamente, porém - não deve ser uma grande preocupação.