gpt4 book ai didi

mysql - 在 MySQL 中使用 NHibernate guid.comb 主键时如何避免碎片?

转载 作者:行者123 更新时间:2023-11-29 02:03:09 31 4
gpt4 key购买 nike

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

MySQL 没有专用的 GUID 数据类型,新的数据库模式使用 BINARY(16) 作为所有标识符。在不对 NHibernate 映射进行任何更改的情况下,我可以启动我们的应用程序,保留新实体并将它们从 MySQL 数据库中加载回来。伟大的!然而,事实证明,按顺序生成的 GUID 在 BINARY(16) 列中的排序非常不按顺序,从而产生了 Not Acceptable 索引碎片。

阅读这个问题,结果是 MSSQL has a quite special method for sorting GUIDs . 16 个字节首先按最后六个字节排序,然后按反向组中的前面排序,而我的 naïve MySQL 实现首先按第一个字节排序,然后是下一个字节,依此类推。

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

最佳答案

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

NHibernate 允许我们定义自定义数据类型,可用于数据库和对象之间的映射。我已经实现了一个 BinaryGuidType,它能够对 Guid.ToByteArray() 产生的字节进行重新排序。根据 MSSQL 对 GUID 进行排序并将它们重新排序为 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 个新对象,它们完全顺序存储,没有索引碎片的迹象。

关于mysql - 在 MySQL 中使用 NHibernate guid.comb 主键时如何避免碎片?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11394305/

31 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com