sql-server – 使用BINARY(16)代替UNIQUEIDENTIFIER是否会受到惩罚?

前端之家收集整理的这篇文章主要介绍了sql-server – 使用BINARY(16)代替UNIQUEIDENTIFIER是否会受到惩罚?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我最近继承了一个sql Server数据库,该数据库使用BINARY(16)而不是UNIQUEIDENTIFIER来存储Guids.它为包括主键在内的所有内容执行此操作

我应该担心吗?

解决方法

Should I be concerned?

嗯,这里有一些事情有点令人担忧.

首先:虽然UNIQUEIDENTIFIER(即Guid)确实是一个16字节的二进制值,但它也是如此:

>所有数据都可以二进制形式存储(例如INT可以存储在BINARY(4)中,DATETIME可以存储在BINARY(8)中),因此#2↴
>除了方便之外,为GUID提供单独的数据类型可能是有原因的(例如,sysname作为NVARCHAR(128)的别名).

我能找到的三个行为差异是:

>比较sql Server中的UNIQUEIDENTIFIER值,无论好坏,实际上并不像比较BINARY(16)值那样.根据Comparing GUID and uniqueidentifier Values的MSDN页面,比较sql Server中的UNIQUEIDENTIFIER值:

the last six bytes of a value are most significant

>虽然这些值不经常排序,但这两种类型之间存在细微差别.根据uniqueidentifier的MSDN页面

ordering is not implemented by comparing the bit patterns of the two values.

>鉴于sql Server和.NET之间处理GUID值的方式存在差异(在上面链接的“比较GUID和uniqueidentifier值”页面中注明),将此数据从sql Server中提取到应用程序代码中可能无法正确处理在应用程序代码中,如果需要模拟sql Server比较行为.可以通过转换为sqlGuid来模拟该行为,但开发人员是否知道这样做?

第二:基于以下声明

It does this for everything including primary keys.

通过使用GUID作为PK而不是使用备用密钥以及使用INT或甚至BIGINT作为PK,我会关注系统性能.如果这些GUID PK是聚集索引,则更为关注.

UPDATE

以下由O.P.对@ Rob的回答发表的评论提出了另一个问题:

it was migrated from I think MysqL

GUID可以存储在2 different binary formats.因此,可能会引起关注,具体取决于:

>生成二进制表示的系统,和
>如果字符串值在原始系统之外使用,例如在应用程序代码中或提供给客户端以在导入文件中使用等.

生成二进制表示的问题与4个“字段”中前3个的字节顺序有关.如果您按照上面的链接访问Wikipedia文章,您将看到RFC 4122指定对所有4个字段使用“Big Endian”编码,但Microsoft GUID指定使用“Native”Endianness.那么,英特尔架构是Little Endian,因此前三个字段的字节顺序与RFC之后的系统(以及在Big Endian系统上生成的Microsoft样式的GUID)相反.第一个字段“数据1”是4个字节.在一个Endianness中,它将表示为(假设)0x01020304.但在另一个Endianness中它将是0x04030201.因此,如果使用0x01020304二进制表示法从导入文件填充当前数据库的BINARY(16)字段,并且在RFC之后的系统上生成二进制表示,则将当前在BINARY(16)字段中的数据转换为UNIQUEIDENTIFIER将导致在与最初创建的GUID不同的GUID中.如果值永远不会离开数据库,这实际上不会造成问题,并且只会比较值是否相等而不是排序.

对排序的关注只是在转换为UNIQUEIDENTIFIER后它们不会处于相同的顺序.幸运的是,如果原始系统确实是MysqL,那么首先从未对二进制表示进行排序,因为MysqL只有字符串表示UUID.

如果二进制表示是在Windows / sql Server之外生成的,那么对数据库外部使用的字符串值的关注也会更严重.由于字节排序可能不同,因此字符串形式的相同GUID将导致2种不同的二进制表示形式,具体取决于发生转换的位置.如果应用程序代码或客户被赋予字符串形式的GUID,因为ABC来自123的二进制形式,并且二进制表示是在遵循RFC的系统上生成的,那么相同的二进制表示(即123)将转换为字符串形式转换为UNIQUEIDENTIFIER时的DEF.同样,当转换为UNIQUEIDENTIFIER时,ABC的原始字符串形式将转换为456的二进制形式.

因此,如果GUID从未离开过数据库,那么在排序之外没有太多需要关注的问题.或者,如果MysqL的导入是通过转换字符串形式(即FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40)完成的,那么它可能没问题.另外,如果将这些GUID提供给客户或应用程序代码,您可以通过获取一个GUID并通过SELECT CONVERT(UNIQUEIDENTIFIER,’在数据库之外找到的值’)进行转换来测试它们如何转换;看看你是否找到了预期的记录.如果您无法匹配记录,则可能必须将字段保留为BINARY(16).

很可能没有问题,但我提到这一点,因为在适当的条件下可能存在问题.

如何插入新的GUID?在应用代码生成

更新2

如果先前对导入在另一个系统上生成的GUID的二进制表示形式的潜在问题的解释有点(或很多)令人困惑,那么希望以下内容会更加清晰:

DECLARE @GUID UNIQUEIDENTIFIER = NEWID();
SELECT @GUID AS [String],CONVERT(BINARY(16),@GUID) AS [Binary];
-- String = 5FED23BE-E52C-40EE-8F45-49664C9472FD
-- Binary = 0xBE23ED5F2CE5EE408F4549664C9472FD
--          BE23ED5F-2CE5-EE40-8F45-49664C9472FD

在上面显示输出中,“String”和“Binary”值来自相同的GUID. “二进制”行下面的值与“二进制”行的值相同,但格式与“字符串”行相同(即删除“0x”并添加四个短划线).比较第一个和第三个值,它们不完全相同,但它们非常接近:最右边的两个部分是相同的,但最左边的三个部分不相同.但是如果仔细观察,你可以看到三个部分中的每个部分都是相同的字节,只是顺序不同.可能更容易看出我是否只显示前三个部分,并对字节进行编号,以便更容易看出它们的顺序在两个表示之间的差异:

String = 15F2ED3234BE – 5E562C – 7408EE
二进制= 4BE3232ED15F – 62C5E5 – 8EE740(在Windows / sql Server中)

因此,在每个分组中,字节的顺序是相反的,但仅在Windows和sql Server中.但是,在遵循RFC的系统上,二进制表示将镜像sting表示,因为不会有任何字节顺序的反转.

如何将数据从MysqL引入sql Server?以下是一些选择:

SELECT CONVERT(BINARY(16),'5FED23BE-E52C-40EE-8F45-49664C9472FD'),0x5FED23BEE52C40EE8F4549664C9472FD),CONVERT(UNIQUEIDENTIFIER,'5FED23BE-E52C-40EE-8F45-49664C9472FD'));

返回:

0x35464544323342452D453532432D3430  
0x5FED23BEE52C40EE8F4549664C9472FD  
0xBE23ED5F2CE5EE408F4549664C9472FD

假设它是直接二进制到二进制(即上面的转换#2),那么生成的GUID(如果转换为实际的UNIQUEIDENTIFIER)将是:

SELECT CONVERT(UNIQUEIDENTIFIER,0x5FED23BEE52C40EE8F4549664C9472FD);

返回:

BE23ED5F-2CE5-EE40-8F45-49664C9472FD

这是错的.这给我们留下了三个问题:

>如何将数据导入sql Server?>应用程序代码用什么语言编写?>运行应用程序代码的平台是什么?

猜你在找的MsSQL相关文章