【问题标题】:How to avoid fragmentation when using NHibernate guid.comb primary key in MySQL?在 MySQL 中使用 NHibernate guid.comb 主键时如何避免碎片?
【发布时间】:2012-07-09 11:39:32
【问题描述】:

我正在将数据库从 Microsoft SQL Server 迁移到 MySQL/MariaDB。在 MSSQL 上,数据库对所有主键使用 uniqueidentifier (GUID) 数据类型。 NHibernate用于数据库和应用程序之间的数据映射,GUID生成采用guid.comb策略避免聚集索引的碎片化。

MySQL 没有专用的 GUID 数据类型,新的数据库架构对所有标识符使用 BINARY(16)。无需对 NHibernate 映射进行任何更改,我就可以启动我们的应用程序,持久化新实体并​​从 MySQL 数据库加载它们。伟大的!然而,事实证明,按顺序生成的 GUID 在BINARY(16) 列中的排序非常不按顺序排列,从而产生不可接受的索引碎片。

阅读了这个问题,原来是MSSQL has a quite special method for sorting GUIDs。这 16 个字节首先按最后 6 个字节排序,然后按倒序排列,而我的幼稚 MySQL 实现首先按第一个字节排序,然后是下一个字节,依此类推。

这引出了我的问题:如何避免 MySQL 数据库中的这种碎片,同时保留现有的 GUID 和 guid.comb 策略?我自己有一个解决方案的想法(发布在下面),但我不禁觉得我可能错过了一些东西。当然,其他人一定以前处理过这个问题,也许有一个简单的方法可以解决它。

【问题讨论】:

    标签: mysql sql-server nhibernate


    【解决方案1】:

    作为observed by Alberto Ferraridiscussed here on StackOverflow,Microsoft SQL Server 通过按特定顺序比较字节来对GUID 进行排序。由于 MySQL 会对 BINARY(16) "straight-foward" 进行排序,我们需要做的就是在读取/写入数据库时​​重新排序字节。

    NHibernate 允许我们定义自定义数据类型,可用于数据库和对象之间的映射。我已经实现了一个BinaryGuidType,它能够根据MSSQL 对GUID 的排序方式对Guid.ToByteArray() 产生的字节进行重新排序,并将它们重新排序为Guid(byte[]) 构造函数所接受的格式。

    字节顺序如下:

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

    System.Guid 保存到BINARY(16) 如下所示:

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

    将字节读回System.Guid 如下所示:

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

    Full source code for the BinaryGuidType here.

    这似乎运作良好。在一个表中创建和持久化 10.000 个新对象,它们完全按顺序存储,没有索引碎片的迹象。

    【讨论】:

      猜你喜欢
      • 2010-09-14
      • 1970-01-01
      • 1970-01-01
      • 2023-03-02
      • 1970-01-01
      • 2013-03-28
      • 2023-03-13
      • 1970-01-01
      • 2011-01-01
      相关资源
      最近更新 更多