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


19

我最近继承了一个SQL Server数据库,该数据库用于BINARY(16)而不是UNIQUEIDENTIFIER存储Guid。它对包括主键在内的所有内容执行此操作。

我应该担心吗?


是否在整个过程中始终使用binary(16)?包括变量和参数?如果不是,则需要考虑隐式强制转换的效果。
马丁·史密斯

是的,值得庆幸的是,我也不必处理隐式强制转换。
乔纳森·艾伦

Answers:


21

我应该担心吗?

好吧,这里有些事情有点令人担忧。

首先:虽然UNIQUEIDENTIFIERGuid是)是16字节的二进制值,但也确实是:

  1. 所有数据都可以二进制形式存储(例如INT,可以存储在中BINARY(4)DATETIME可以存储在中BINARY(8),等等),因此#2↴
  2. 出于纯粹的方便性,可能有一个GUID具有单独的数据类型的原因(例如,sysname作为的别名NVARCHAR(128))。

我可以发现三种行为差异:

  • 不管UNIQUEIDENTIFIER是好是坏,比较SQL Server中的值实际上与比较BINARY(16)值的方法不同。根据用于比较GUID和uniqueidentifier值的MSDN页面,UNIQUEIDENTIFIER在SQL Server中比较值时:

    值的最后六个字节为最高有效

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

    通过比较两个值的位模式无法实现排序。

  • 鉴于在SQL Server和.NET之间处理GUID值的方式有所不同(在上面的“比较GUID和uniqueidentifier值”页面中有注释),因此在SQL Server中将这些数据从SQL Server提取到应用程序代码中可能无法正确处理。应用程序代码(如果需要模拟SQL Server比较行为)。可以通过转换为来模拟该行为SqlGuid,但是开发人员会知道这样做吗?

第二:基于以下陈述

它对包括主键在内的所有内容执行此操作。

通常,我会通过将GUID用作PK而不是替代键以及同时使用an INT或什BIGINT至PK 来关注系统性能。甚至更担心这些GUID PK是否为聚簇索引。

更新

OP对@Rob的回答提出的以下评论引起了另外一个关注:

它是从我认为MySQL迁移过来的

GUID可以2种不同的二进制格式存储。因此,可能会引起关注,具体取决于:

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

生成二进制表示形式的问题与4个“字段”中前3个字节的字节顺序有关。如果您单击上面指向Wikipedia文章的链接,您将看到RFC 4122指定对所有4个字段使用“大尾数”编码,而Microsoft GUID指定使用“本机”尾数。嗯,Intel体系结构是Little Endian,因此前3个字段的字节顺序与遵循RFC(以及在Big Endian系统上生成的Microsoft样式的GUID)的系统相反。第一个字段“数据1”为4个字节。在一个字节序中,它将(假设地)表示为0x01020304。但是在另一种Endianness中将会是0x04030201。所以如果当前数据库BINARY(16)该二进制表示是在遵循RFC的系统上生成的,然后将该BINARY(16)字段中当前的数据转换为,UNIQUEIDENTIFIER将导致GUID与最初创建的GUID不同。如果这些值从未离开数据库,并且只比较了这些值的相等性而不是排序,那么这实际上不会带来问题。

有关排序的问题只是简单地转换为后,它们将不会处于相同的顺序UNIQUEIDENTIFIER。幸运的是,如果原始系统确实是MySQL,则首先无需对二进制表示形式进行排序,因为MySQL仅具有UUID的字符串表示形式。

同样,如果二进制表示是在Windows / SQL Server之外生成的,那么在数据库之外使用字符串值的问题会更加严重。由于字节顺序可能有所不同,因此相同的字符串形式的GUID将导致2种不同的二进制表示形式,具体取决于转换发生的位置。如果应用程序的代码或客户给予在串形式的GUID作为ABC从的二进制形式来123 二进制表示的系统上产生以下的RFC,那么同一二进制表示(即123)将转化成的字符串形式DEF,当转换成一个UNIQUEIDENTIFIER。同样,当转换为时,原始字符串形式ABC将转换为二进制形式。456UNIQUEIDENTIFIER

因此,如果GUID从未离开数据库,那么在订购之外就无需担心太多了。或者,如果从MySQL导入是通过转换字符串形式(即FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40)完成的,则可能没问题。否则,如果将这些GUID提供给客户或在应用程序代码中,则可以通过获取一个GUID并通过进行转换,以测试它们的转换方式,SELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');并查看是否找到了预期的记录。如果您无法匹配记录,则可能必须将字段保留为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”并添加了四个破折号)。比较第一个值和第三个值,它们并不完全相同,但是它们非常接近:最右边的两个部分相同,而最左边的三个部分不同。但是,如果仔细观察,您会发现三个部分中的每个部分都具有相同的字节,只是顺序不同。如果仅显示前三个部分并为字节编号,可能会更容易看到,因此更容易看出两种表示形式之间的顺序差异:

字符串= 1 5F 2 ED 3 23 4 BE 5 E5 6 2C 7 40 8 EE
二进制= 4 BE 3 23 2 ED 1 5F 6 2C 5 E5 8 EE 7 40(在Windows / SQL Server中)

因此,在每个分组中,字节的顺序是相反的,但仅在Windows和SQL Server中是相反的。但是,在遵循RFC的系统上,二进制表示形式将镜像字符串表示形式,因为字节顺序不会发生任何反转。

如何将数据从MySQL带入SQL Server?这里有一些选择:

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

返回值:

0x35464544323342452D453532432D3430  
0x5FED23BEE52C40EE8F4549664C9472FD  
0xBE23ED5F2CE5EE408F4549664C9472FD

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

SELECT CONVERT(UNIQUEIDENTIFIER, 0x5FED23BEE52C40EE8F4549664C9472FD);

返回值:

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

哪有错 这给我们留下了三个问题:

  1. 如何将数据导入SQL Server?
  2. 应用程序代码用什么语言编写?
  3. 应用程序代码在哪个平台上运行?

我假定GUID是在应用程序中生成的,因为我在数据库中看不到它们。
乔纳森·艾伦

我不能说我完全遵循有关字节顺序的说明,但这使我考虑了索引。与二进制相比,uniqueidentifier会更可能导致索引碎片化吗?
乔纳森·艾伦

2
@JonathanAllen我添加了另一个UPDATE部分,希望可以更好地进行解释。不,索引在它们之间应该没有任何不同。
所罗门·鲁兹基

“非常感谢”,SQL Server不会在变式1和变式2之间更改顺序-即使“可以”以不同的方式存储在磁盘上,也始终使混乱的顺序相同。
user2864740

5

您永远可以关注。;)

该系统可能已从不支持uniqueidentifier的其他系统迁移而来。您还有其他未知的妥协吗?

设计者可能不了解uniqueidentifier类型。他们还不知道其他什么?

从技术上讲,这不是主要问题。


是的,它是从我认为MySQL迁移过来的。是的,有很多有趣的东西要看。
乔纳森·艾伦
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.