Mysql
 sql >> Database >  >> RDS >> Mysql

Come evitare la frammentazione quando si utilizza la chiave primaria NHibernate guid.comb in MySQL?

Come osservato da Alberto Ferrari e discusso qui su StackOverflow , Microsoft SQL Server ordina i GUID confrontando i byte in un ordine specifico. Poiché MySQL ordinerà un BINARY(16) "semplicemente", tutto ciò che dobbiamo fare è riordinare i byte durante la lettura/scrittura nel database.

NHibernate ci consente di definire tipi di dati personalizzati, che possono essere utilizzati nelle mappature tra database e oggetti. Ho implementato un BinaryGuidType , in grado di riordinare i byte prodotti da Guid.ToByteArray() in base al modo in cui MSSQL ordina i GUID e li riordina nel formato accettato da Guid(byte[]) costruttore.

L'ordine dei byte è simile al seguente:

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

Salvataggio di un System.Guid a un BINARY(16) va così:

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);

Rileggere i byte in un System.Guid va così:

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];
}

Codice sorgente completo per BinaryGuidType qui.

Questo sembra funzionare bene. Creando e rendendo persistenti 10.000 nuovi oggetti in una tabella, vengono archiviati in modo completamente sequenziale, senza segni di frammentazione dell'indice.