sql >> Base de Datos >  >> RDS >> Mysql

¿Cómo evitar la fragmentación al usar la clave principal NHibernate guid.comb en MySQL?

Como observado por Alberto Ferrari y discutido aquí en StackOverflow , Microsoft SQL Server ordena los GUID comparando los bytes en un orden específico. Como MySQL ordenará un BINARY(16) "sencillo", todo lo que tenemos que hacer es reordenar los bytes al leer/escribir en la base de datos.

NHibernate nos permite definir tipos de datos personalizados, que se pueden usar en asignaciones entre la base de datos y los objetos. He implementado un BinaryGuidType , capaz de reordenar los bytes producidos por Guid.ToByteArray() de acuerdo con la forma en que MSSQL ordena los GUID y los vuelve a ordenar en el formato aceptado por Guid(byte[]) constructor.

El orden de bytes se ve así:

int[] ByteOrder = new[] { 10,11,12,13,14,15,8,9,6,7,4,5,0,1,2,3 };

Guardar un System.Guid a un BINARY(16) va así:

var bytes = ((Guid) value).ToByteArray();
var reorderedBytes = new byte[16];

for (var i = 0; i < 16; i++)
{
    reorderedBytes[i] = bytes[ByteOrder[i]];
}

NHibernateUtil.Binary.NullSafeSet(cmd, reorderedBytes, index);

Leer los bytes de nuevo en un System.Guid va así:

var bytes = (byte[]) NHibernateUtil.Binary.NullSafeGet(rs, names[0]);
if (bytes == null || bytes.Length == 0) return null;

var reorderedBytes = new byte[16];

for (var i = 0 ; i < 16; i++)
{
    reorderedBytes[ByteOrder[i]] = bytes[i];
}

Código fuente completo para BinaryGuidType aquí.

Esto parece funcionar bien. Creando y conservando 10.000 objetos nuevos en una tabla, se almacenan de forma completamente secuencial, sin signos de fragmentación del índice.