Comme observé par Alberto Ferrari
et discuté ici sur StackOverflow
, Microsoft SQL Server trie les GUID en comparant les octets dans un ordre spécifique. Comme MySQL triera un BINARY(16)
"directement", tout ce que nous avons à faire, c'est de réorganiser les octets lors de la lecture/écriture dans la base de données.
NHibernate nous permet de définir des types de données personnalisés, qui peuvent être utilisés dans les mappages entre la base de données et les objets. J'ai implémenté un BinaryGuidType
, capable de réorganiser les octets produits par Guid.ToByteArray()
selon la façon dont MSSQL trie les GUID et les réorganise dans le format accepté par Guid(byte[])
constructeur.
L'ordre des octets ressemble à ceci :
int[] ByteOrder = new[] { 10,11,12,13,14,15,8,9,6,7,4,5,0,1,2,3 };
Enregistrement d'un System.Guid
à un BINARY(16)
va comme ceci :
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);
Lecture des octets dans un System.Guid
va comme ceci :
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];
}
Code source complet pour le BinaryGuidType
ici.
Cela semble bien fonctionner. Créant et conservant 10 000 nouveaux objets dans une table, ils sont stockés de manière complètement séquentielle, sans aucun signe de fragmentation d'index.