鉴于 SQL Server 和 .NET 之间处理 GUID 值的方式存在差异(在上面链接的“比较 GUID 和唯一标识符值”页面中指出),将这些数据从 SQL Server 拉出到应用程序代码中可能无法正确处理如果需要模拟 SQL Server 比较行为,请使用应用程序代码。可以通过转换为 a 来模拟这种行为SqlGuid,但开发人员会知道这样做吗?
生成二进制表示的问题与 4 个“字段”中的前 3 个的字节顺序有关。如果您按照上面的链接访问 Wikipedia 文章,您将看到 RFC 4122 指定对所有 4 个字段使用“Big Endian”编码,但 Microsoft GUID 指定使用“Native”Endianness。嗯,英特尔架构是 Little Endian,因此前 3 个字段的字节顺序与遵循 RFC 的系统(以及在 Big Endian 系统上生成的 Microsoft 风格的 GUID)相反。第一个字段“Data 1”是 4 个字节。在一个字节序中,它将被表示为(假设地)0x01020304。但在另一个 Endianness 中它会是0x04030201. 所以如果当前数据库'BINARY(16)该二进制表示是在遵循 RFC 的系统上生成的,然后将当前BINARY(16)字段中的数据转换为 aUNIQUEIDENTIFIER将导致与最初创建的 GUID 不同。如果这些值从未离开数据库,并且这些值仅被比较是否相等而不是排序,这不会真正造成问题。
排序的问题很简单,转换为UNIQUEIDENTIFIER. 幸运的是,如果原始系统真的是 MySQL,那么首先就不会对二进制表示进行排序,因为 MySQL 只有UUID的字符串表示。
同样,如果二进制表示是在 Windows / SQL Server 之外生成的,那么在数据库之外使用的字符串值的问题就会更加严重。由于字节顺序可能不同,因此字符串形式的相同 GUID 将导致 2 种不同的二进制表示,具体取决于转换发生的位置。ABC如果为应用程序代码或客户提供了来自二进制形式的字符串形式的 GUID ,123并且二进制表示是在遵循 RFC 的系统上生成的,那么当转换为时,相同的二进制表示(即123)将转换为字符串形式DEF一个UNIQUEIDENTIFIER。同样,ABC当456转换为UNIQUEIDENTIFIER.
因此,如果 GUID 从未离开数据库,那么除了排序之外就没有什么可担心的了。或者,如果从 MySQL 导入是通过转换字符串形式(即FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40)完成的,那么它可能没问题。否则,如果将这些 GUID 提供给客户或在应用程序代码中,您可以通过获取一个并转换通过SELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');并查看是否找到预期记录来测试它们如何转换。如果您无法匹配记录,那么您可能必须将字段保留为BINARY(16).
好吧,这里有几件事有点令人担忧。
第一:虽然 a
UNIQUEIDENTIFIER
(ieGuid
) 确实是一个 16 字节的二进制值,但也确实:INT
可以存储在 中BINARY(4)
,DATETIME
可以存储在 中BINARY(8)
,等等),因此 #2 ↴sysname
,作为 的别名NVARCHAR(128)
)。我能找到的三个行为差异是:
在 SQL Server 中比较
UNIQUEIDENTIFIER
值,无论好坏,实际上与比较BINARY(16)
值的方式不同。根据Comparing GUID and uniqueidentifier Values的 MSDN 页面,在比较UNIQUEIDENTIFIER
SQL Server 中的值时:虽然这些值不经常排序,但这两种类型之间存在细微差别。根据uniqueidentifier的 MSDN 页面:
鉴于 SQL Server 和 .NET 之间处理 GUID 值的方式存在差异(在上面链接的“比较 GUID 和唯一标识符值”页面中指出),将这些数据从 SQL Server 拉出到应用程序代码中可能无法正确处理如果需要模拟 SQL Server 比较行为,请使用应用程序代码。可以通过转换为 a 来模拟这种行为
SqlGuid
,但开发人员会知道这样做吗?第二:基于以下陈述
我一般会关注系统性能,方法是将 GUID 用作 PK 而不是备用键,同时使用一个
INT
或什BIGINT
至作为 PK。如果这些 GUID PK 是聚集索引,则更令人担忧。更新
OP 对@Rob 的回答发表的以下评论引发了额外的担忧:
GUID 可以以2 种不同的二进制格式存储。因此,可能会引起关注,具体取决于:
生成二进制表示的问题与 4 个“字段”中的前 3 个的字节顺序有关。如果您按照上面的链接访问 Wikipedia 文章,您将看到 RFC 4122 指定对所有 4 个字段使用“Big Endian”编码,但 Microsoft GUID 指定使用“Native”Endianness。嗯,英特尔架构是 Little Endian,因此前 3 个字段的字节顺序与遵循 RFC 的系统(以及在 Big Endian 系统上生成的 Microsoft 风格的 GUID)相反。第一个字段“Data 1”是 4 个字节。在一个字节序中,它将被表示为(假设地)
0x01020304
。但在另一个 Endianness 中它会是0x04030201
. 所以如果当前数据库'BINARY(16)
该二进制表示是在遵循 RFC 的系统上生成的,然后将当前BINARY(16)
字段中的数据转换为 aUNIQUEIDENTIFIER
将导致与最初创建的 GUID 不同。如果这些值从未离开数据库,并且这些值仅被比较是否相等而不是排序,这不会真正造成问题。排序的问题很简单,转换为
UNIQUEIDENTIFIER
. 幸运的是,如果原始系统真的是 MySQL,那么首先就不会对二进制表示进行排序,因为 MySQL 只有UUID的字符串表示。同样,如果二进制表示是在 Windows / SQL Server 之外生成的,那么在数据库之外使用的字符串值的问题就会更加严重。由于字节顺序可能不同,因此字符串形式的相同 GUID 将导致 2 种不同的二进制表示,具体取决于转换发生的位置。
ABC
如果为应用程序代码或客户提供了来自二进制形式的字符串形式的 GUID ,123
并且二进制表示是在遵循 RFC 的系统上生成的,那么当转换为时,相同的二进制表示(即123
)将转换为字符串形式DEF
一个UNIQUEIDENTIFIER
。同样,ABC
当456
转换为UNIQUEIDENTIFIER
.因此,如果 GUID 从未离开数据库,那么除了排序之外就没有什么可担心的了。或者,如果从 MySQL 导入是通过转换字符串形式(即
FCCEC3D8-22A0-4C8A-BF35-EC18227C9F40
)完成的,那么它可能没问题。否则,如果将这些 GUID 提供给客户或在应用程序代码中,您可以通过获取一个并转换通过SELECT CONVERT(UNIQUEIDENTIFIER, 'value found outside of the database');
并查看是否找到预期记录来测试它们如何转换。如果您无法匹配记录,那么您可能必须将字段保留为BINARY(16)
.很可能不会有问题,但我之所以提到这一点,是因为在适当的条件下可能会出现问题。
以及如何插入新的 GUID?在应用程序代码中生成?
更新 2
如果前面对与导入在另一个系统上生成的 GUID 的二进制表示相关的潜在问题的解释有点(或很多)令人困惑,希望以下内容会更清楚一点:
在上面显示的输出中,“String”和“Binary”值来自同一个 GUID。“Binary”行下方的值与“Binary”行的值相同,但格式与“String”行相同(即删除“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 的?这里有几个选择:
回报:
假设它是直接的二进制到二进制(即上面的 Convert #2),那么如果转换为实际的 GUID,则生成的 GUID
UNIQUEIDENTIFIER
将是:回报:
这是错误的。这给我们留下了三个问题:
你总是可以担心的。;)
该系统可能是从其他不支持唯一标识符的系统迁移而来的。还有其他你不知道的妥协吗?
设计者可能不知道 uniqueidentifier 类型。还有什么他们不知道的?
但从技术上讲 - 这不应该是一个主要问题。