J'ai récemment hérité d'une base de données SQL Server qui utilise BINARY(16)
au lieu de UNIQUEIDENTIFIER
pour stocker des Guids. Il le fait pour tout, y compris les clés primaires.
Dois-je m'inquiéter?
sql-server
migration
uuid
Jonathan Allen
la source
la source
Réponses:
Eh bien, il y a deux ou trois choses qui sont un peu préoccupantes.
Premièrement: s'il est vrai que a
UNIQUEIDENTIFIER
(ieGuid
) est une valeur binaire de 16 octets, il est également vrai que:INT
pourraient être stockées dansBINARY(4)
,DATETIME
peuvent être stockées dansBINARY(8)
, etc.), d'où # 2 ↴sysname
comme alias pourNVARCHAR(128)
).Les trois différences de comportement que je peux trouver sont:
La comparaison des
UNIQUEIDENTIFIER
valeurs dans SQL Server, pour le meilleur ou pour le pire, ne se fait pas en fait de la même manière que la comparaison desBINARY(16)
valeurs. Selon la page MSDN pour la comparaison des valeurs GUID et uniqueidentifier , lors de la comparaison desUNIQUEIDENTIFIER
valeurs dans SQL Server:Bien que ces valeurs ne soient pas fréquemment triées, il existe une légère différence entre ces deux types. Selon la page MSDN pour uniqueidentifier :
Étant donné qu'il existe des différences dans la façon dont les valeurs GUID sont traitées entre SQL Server et .NET (noté dans la page "Comparaison des valeurs GUID et uniqueidentifier" liée ci-dessus), l'extraction de ces données de SQL Server dans le code d'application peut ne pas être traitée correctement dans le code d'application si vous devez émuler le comportement de comparaison SQL Server. Ce comportement peut être émulé en le convertissant en un
SqlGuid
, mais un développeur le saurait-il?Deuxièmement: sur la base de la déclaration suivante
Je serais préoccupé en général pour les performances du système en utilisant des GUID en tant que PK plutôt qu'en tant que clés alternatives avec l'utilisation d'un
INT
ou même enBIGINT
tant que PK. Et encore plus préoccupé si ces PK GUID sont les index clusterisés.MISE À JOUR
Le commentaire suivant, fait par le PO sur la réponse de @ Rob, soulève une préoccupation supplémentaire:
Les GUID peuvent être stockés dans 2 formats binaires différents . Ainsi, il pourrait y avoir lieu de s'inquiéter selon:
Le problème avec l'endroit où la représentation binaire a été générée a à voir avec l'ordre des octets des 3 premiers des 4 "champs". Si vous suivez le lien ci-dessus pour l'article Wikipedia, vous verrez que la RFC 4122 spécifie d'utiliser le codage "Big Endian" pour les 4 champs, mais les GUID Microsoft spécifient l'utilisation de l'endianness "Native". Eh bien, l'architecture Intel est Little Endian, donc l'ordre des octets pour les 3 premiers champs est inversé à partir des systèmes suivant la RFC (ainsi que les GUID de style Microsoft générés sur les systèmes Big Endian). Le premier champ, "Data 1", est de 4 octets. Dans un endianisme, il serait représenté (hypothétiquement)
0x01020304
. Mais dans l'autre Endianness ce serait0x04030201
. Donc, si la base de données actuelle "BINARY(16)
cette représentation binaire a été générée sur un système suivant le RFC, puis la conversion des données actuellement sur leBINARY(16)
terrain en unUNIQUEIDENTIFIER
aura pour résultat un GUID différent de ce qui a été créé à l'origine. Cela ne pose pas vraiment de problème SI les valeurs n'ont jamais quitté la base de données, et les valeurs ne sont jamais comparées que pour l'égalité et non pour l'ordre.Le problème avec la commande est simplement qu'ils ne seront pas dans le même ordre après la conversion
UNIQUEIDENTIFIER
. Heureusement, si le système d'origine était vraiment MySQL, la commande n'a jamais été effectuée sur la représentation binaire en premier lieu puisque MySQL n'a qu'une représentation sous forme de chaîne d' UUID .Le problème avec les valeurs de chaîne utilisées en dehors de la base de données est encore plus grave si la représentation binaire a été générée en dehors de Windows / SQL Server. Étant donné que l'ordre des octets est potentiellement différent, le même GUID sous forme de chaîne entraînerait 2 représentations binaires différentes, selon l'endroit où cette conversion a eu lieu. Si le code d'application ou les clients recevaient un GUID sous forme de chaîne comme
ABC
provenant d'une forme binaire de123
et que la représentation binaire était générée sur un système suivant la RFC, alors cette même représentation binaire (c.-à-d.123
) Se traduirait sous forme de chaîneDEF
lorsqu'elle sera convertie en aUNIQUEIDENTIFIER
. De même, la forme de chaîne d'origine deABC
serait convertie en une forme binaire456
lorsqu'elle est convertie en aUNIQUEIDENTIFIER
.Donc, si les GUID n'ont jamais quitté la base de données, il n'y a pas grand-chose à craindre en dehors de la commande. Ou, si l'importation à partir de MySQL a été effectuée en convertissant la forme de chaîne (c'est-à-dire
FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40
), cela peut être correct. Sinon, si ces GUID ont été donnés aux clients ou dans le code de l'application, vous pouvez tester pour voir comment ils se convertissent en en obtenant un et en convertissant viaSELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');
et voir si vous trouvez l'enregistrement attendu. Si vous ne pouvez pas faire correspondre les enregistrements, vous devrez peut-être conserver les champs sousBINARY(16)
.Selon toute vraisemblance, il n'y aura pas de problème, mais je le mentionne parce que dans les bonnes conditions, il pourrait y avoir un problème.
Et comment les nouveaux GUID sont-ils insérés de toute façon? Généré dans le code de l'application?
MISE À JOUR 2
Si l'explication précédente du problème potentiel lié à l'importation de représentations binaires de GUID générées sur un autre système était un peu (ou beaucoup) confuse, j'espère que ce qui suit sera un peu plus clair:
Dans la sortie illustrée ci-dessus, les valeurs "String" et "Binary" proviennent du même GUID. La valeur sous la ligne "Binaire" est la même valeur que la ligne "Binaire", mais formatée dans le même style que la ligne "Chaîne" (c'est-à-dire supprimé "0x" et ajouté les quatre tirets). En comparant les première et troisième valeurs, elles ne sont pas exactement les mêmes, mais elles sont très proches: les deux sections les plus à droite sont identiques, mais les trois sections les plus à gauche ne le sont pas. Mais si vous regardez attentivement, vous pouvez voir que ce sont les mêmes octets dans chacune des trois sections, juste dans un ordre différent. Il pourrait être plus facile de voir si je ne montre que ces trois premières sections et de numéroter les octets, il est donc plus facile de voir comment leur ordre diffère entre les deux représentations:
Chaîne = 1 5F 2 ED 3 23 4 BE - 5 E5 6 2C - 7 40 8 EE
Binaire = 4 BE 3 23 2 ED 1 5F - 6 2C 5 E5 - 8 EE 7 40 (sous Windows / SQL Server)
Ainsi, au sein de chaque regroupement, l'ordre des octets est inversé, mais uniquement dans Windows et également SQL Server. Cependant, sur un système qui adhère à la RFC, la représentation binaire refléterait la représentation sting car il n'y aurait pas d'inversion de l'ordre des octets.
Comment les données ont-elles été importées dans SQL Server à partir de MySQL? Voici quelques choix:
Retour:
En supposant qu'il s'agissait d'un simple binaire en binaire (c'est-à-dire Convert # 2 ci-dessus), le GUID résultant, s'il était converti en un réel
UNIQUEIDENTIFIER
, serait:Retour:
Ce qui est faux. Et cela nous laisse avec trois questions:
la source
Vous pouvez toujours être inquiet. ;)
Le système peut avoir été migré à partir d'un autre système qui ne prend pas en charge uniqueidentifier. Y a-t-il d'autres compromis que vous ne connaissez pas?
Le concepteur peut ne pas connaître le type d'identificateur unique. Quelles autres choses ignoraient-ils?
Techniquement, cela ne devrait pas être une préoccupation majeure.
la source