Recientemente heredé una base de datos de SQL Server que usa en BINARY(16)
lugar de UNIQUEIDENTIFIER
almacenar Guías. Hace esto para todo, incluidas las claves principales.
¿Debería Preocuparme?
sql-server
migration
uuid
Jonathan Allen
fuente
fuente
Respuestas:
Bueno, hay un par de cosas aquí que son un poco preocupantes.
Primero: si bien es cierto que un
UNIQUEIDENTIFIER
(es decirGuid
) es un valor binario de 16 bytes, también es cierto que:INT
podrían almacenarse enBINARY(4)
,DATETIME
pueden almacenarse enBINARY(8)
, etc.), por lo tanto, # 2 ↴sysname
como un alias paraNVARCHAR(128)
).Las tres diferencias de comportamiento que puedo encontrar son:
La comparación de
UNIQUEIDENTIFIER
valores en SQL Server, para bien o para mal, en realidad no se hace de la misma manera que la comparación deBINARY(16)
valores. Según la página de MSDN para comparar GUID y valores de identificador único , al compararUNIQUEIDENTIFIER
valores en SQL Server:Si bien estos valores no se ordenan con frecuencia, existe una ligera diferencia entre estos dos tipos. Según la página de MSDN para uniqueidentifier :
Dado que existen diferencias en la forma en que se manejan los valores de GUID entre SQL Server y .NET (anotado en la página "Comparación de valores de GUID y de identificador único" vinculada anteriormente), es posible que extraer estos datos de SQL Server en el código de la aplicación no se aborde correctamente en el código de la aplicación si necesita emular el comportamiento de comparación de SQL Server. Ese comportamiento se puede emular convirtiendo a a
SqlGuid
, pero ¿un desarrollador sabría hacer eso?Segundo: basado en la siguiente declaración
En general, estaría preocupado por el rendimiento del sistema mediante el uso de GUID como PK en lugar de como claves alternativas junto con el uso de
INT
o inclusoBIGINT
como PK. Y aún más preocupado si estos PK GUID son los índices agrupados.ACTUALIZAR
El siguiente comentario, realizado por el OP sobre la respuesta de @ Rob, plantea una preocupación adicional:
Los GUID se pueden almacenar en 2 formatos binarios diferentes . Por lo tanto, podría ser motivo de preocupación dependiendo de:
El problema con el lugar donde se generó la representación binaria tiene que ver con el orden de bytes de los primeros 3 de los 4 "campos". Si sigue el enlace anterior al artículo de Wikipedia, verá que RFC 4122 especifica el uso de la codificación "Big Endian" para los 4 campos, pero los GUID de Microsoft especifican el uso de Endianness "nativo". Bueno, la arquitectura Intel es Little Endian, por lo tanto, el orden de bytes para los primeros 3 campos se invierte de los sistemas que siguen el RFC (así como los GUID de estilo Microsoft generados en los sistemas Big Endian). El primer campo, "Datos 1", es de 4 bytes. En una Endianness se representaría como (hipotéticamente)
0x01020304
. Pero en el otro Endianness lo sería0x04030201
. Entonces, si la base de datos actual 'BINARY(16)
esa representación binaria se generó en un sistema que sigue el RFC, y luego convertir los datos actualmente en elBINARY(16)
campo en unUNIQUEIDENTIFIER
resultado dará un GUID diferente al que se creó originalmente. Esto realmente no plantea un problema SI los valores nunca salieron de la base de datos, y los valores solo se comparan por igualdad y no por orden.La preocupación con el pedido es simplemente que no estarán en el mismo orden después de la conversión
UNIQUEIDENTIFIER
. Afortunadamente, si el sistema original realmente era MySQL, entonces el pedido nunca se realizó en la representación binaria en primer lugar, ya que MySQL solo tiene una representación de cadena de UUID .La preocupación con los valores de cadena que se usan fuera de la base de datos es más grave, de nuevo, si la representación binaria se generó fuera de Windows / SQL Server. Dado que el orden de los bytes es potencialmente diferente, el mismo GUID en forma de cadena daría como resultado 2 representaciones binarias diferentes, dependiendo de dónde tuvo lugar esa conversión. Si el código de la aplicación o los clientes recibieron un GUID en forma de cadena como
ABC
proveniente de una forma binaria123
y la representación binaria se generó en un sistema que sigue al RFC, entonces esa misma representación binaria (es decir123
) se traduciría en una forma de cadena deDEF
cuando se convierte a aUNIQUEIDENTIFIER
. Del mismo modo, la forma de cadena original deABC
se convertiría en una forma binaria de456
cuando se convierte en aUNIQUEIDENTIFIER
.Entonces, si los GUID nunca salieron de la base de datos, entonces no hay mucho de qué preocuparse fuera del pedido. O, si la importación desde MySQL se realizó mediante la conversión de la forma de cadena (es decir
FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40
), entonces podría estar bien. De lo contrario, si se proporcionaron esos GUID a los clientes o en el código de la aplicación, puede probar para ver cómo se convierten obteniendo uno y convirtiendo a travésSELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');
y ver si encuentra el registro esperado. Si no puede hacer coincidir los registros, es posible que deba mantener los campos comoBINARY(16)
.Con toda probabilidad, no habrá un problema, pero lo menciono porque en las condiciones adecuadas podría haber un problema.
¿Y cómo se insertan los nuevos GUID de todos modos? Generado en el código de la aplicación?
ACTUALIZACIÓN 2
Si la explicación anterior del problema potencial relacionado con la importación de representaciones binarias de GUID generadas en otro sistema fue un poco (o mucho) confusa, es de esperar que lo siguiente sea un poco más claro:
En el resultado que se muestra arriba, los valores "String" y "Binary" son del mismo GUID. El valor debajo de la línea "Binary" es el mismo valor que la línea "Binary", pero formateado en el mismo estilo que la línea "String" (es decir, eliminó "0x" y agregó los cuatro guiones). Comparando el primer y el tercer valor, no son exactamente iguales, pero están muy cerca: las dos secciones de la derecha son idénticas, pero las tres secciones de la izquierda no lo son. Pero si observa de cerca, puede ver que son los mismos bytes en cada una de las tres secciones, solo en un orden diferente. Puede ser más fácil ver si muestro solo esas primeras tres secciones y numerar los bytes para que sea más fácil ver cómo su orden difiere entre las dos representaciones:
Cadena = 1 5F 2 ED 3 23 4 BE - 5 E5 6 2C - 7 40 8 EE
Binario = 4 BE 3 23 2 ED 1 5F - 6 2C 5 E5 - 8 EE 7 40 (en Windows / SQL Server)
Entonces, dentro de cada agrupación, el orden de los bytes se invierte, pero solo dentro de Windows y también en SQL Server. Sin embargo, en un sistema que se adhiere a la RFC, la representación binaria reflejaría la representación de picadura porque no habría ninguna inversión del orden de bytes.
¿Cómo se introdujeron los datos en SQL Server desde MySQL? Aquí hay algunas opciones:
Devoluciones:
Suponiendo que fuera directamente binario a binario (es decir, Convertir # 2 arriba), el GUID resultante, si se convierte en un real
UNIQUEIDENTIFIER
, sería:Devoluciones:
Cuál está mal. Y eso nos deja con tres preguntas:
fuente
Siempre puedes estar preocupado. ;)
El sistema puede haberse migrado desde otro sistema que no admite identificador único. ¿Hay otros compromisos que no conoces?
Es posible que el diseñador no haya sabido sobre el tipo de identificador único. ¿Qué otras cosas no sabían?
Técnicamente, sin embargo, no debería ser una gran preocupación.
fuente