Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment éviter la fragmentation lors de l'utilisation de la clé primaire NHibernate guid.comb dans MySQL ?

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.