是的:Windows和.NET采用小端格式。
那么为什么SQL Server采用大端格式呢?很简单:它不是;-)。甚至SQL Server的排序规则和 Unicode 支持页面都指出:
因为 Intel 平台是小端架构,Unicode 代码字符始终以字节交换的方式存储。
那么,当将 Int 值 255 转换时,为什么会得到一个大端二进制值呢?这里存在混淆。这个问题是有缺陷的,因为它基于错误的前提:你应该看到硬件和/或软件的字节序与转换后的值反映相同。但是,为什么你要这么做呢?字节序影响一个值的内部表示方式,即如何存储它。但它并不改变它本身。你可以将 DATETIME 转换为 INT,然后看到一个整数。但是,如果你将该整数保存在 INT 字段中,它将以反向顺序的 4 个字节形式存储,因为这是一个小端系统。但这与你从系统请求该值并显示给你所看到的内容无关。
例如,运行以下命令,以查看将 INT 值 301 转换为 BINARY(2) 的结果为 0x012D,因为 0x012D = 301,即十六进制。因此,将 0x012D 转换回 INT 将返回 301,正如预期的那样。如果原始的 Int 转 Binary 转换给你的是 0x2D01,那么它就不等于 301。
SELECT CONVERT(BINARY(2), 301), CONVERT(INT, 0x012D)
然而,如果您创建了一个包含INT
列的表,并将值"301"插入到该列中,并使用DBCC PAGE
查看数据页在磁盘上的存在方式,则会按照所示的顺序看到以下十六进制数字:
2D 01 00 00
为了回答问题前提的一些证据:
是的,在.NET中执行BitConverter.ToString(BitConverter.GetBytes(255))
会返回:
FF-00-00-00
但这并不是一个转换,因为GetBytes()
没有将“值”进行转换,而是旨在显示内部系统表示形式,这取决于系统是小端还是大端。如果您查看BitConverter.GetBytes的MSDN页面,可能会更清楚它实际上正在做什么。
当转换实际值时,结果在不同系统之间不会(也不能)不同。所有系统(包括计算器)中的整数值256都将始终为0x0100,因为字节序与您在10进制、2进制、16进制等之间转换值无关。
在.NET中,如果要执行此转换,可以使用String.Format("{0:X8}", 255)
,它会返回:
000000FF
这与SELECT CONVERT(BINARY(4), 255);
返回的结果相同,因为它们都将值进行了转换。这个结果没有被显示为Big Endian,而是被显示为它真实的值,这恰好与Big Endian的字节顺序匹配。
换句话说,当以100000000
的位序列开始时,它可以用十进制形式表示为256
,或者用十六进制形式表示(在SQL Server中称为BINARY
/ VARBINARY
)为0x0100
。字节序与此无关,这只是表示相同基础值的不同方式。
当在VARBINARY
和NVARCHAR
之间转换时,可以看到SQL Server是Little Endian的更多证据。由于NVARCHAR
是16位(即2字节)编码,因此我们可以看到字节顺序,因为字符没有数字等效项(不像256 -> 0x0100的示例),所以没有其他要展示的内容(显示Code Point值不可行,因为补充字符问题)。
如下所示,Latin大写字母A
具有U+0041的Code Point(数值上等于65),将转换为VARBINARY
值0x4100
,因为那就是该字符的UTF-16 Little Endian编码值:
SELECT CONVERT(VARBINARY(10), N'A'),
CONVERT(NVARCHAR(5), 0x4100),
CONVERT(INT, 0x4100),
UNICODE(N'A'),
CONVERT(VARBINARY(8), 65);
SELECT CONVERT(VARBINARY(10), N'ᄀ'),
CONVERT(NVARCHAR(5), 0x0011),
CONVERT(INT, 0x0011),
UNICODE(N'ᄀ'),
CONVERT(VARBINARY(8), 4352);
此外,“Pile of Poo”表情符号(代码点U+01F4A9)可以使用代理对“D83D + DCA9”进行查看(NCHAR
函数允许此操作),或者您可以注入UTF-16小端字节序列:
SELECT NCHAR(0xD83D) + NCHAR(0xDCA9) AS [SurrogatePair],
CONVERT(NVARCHAR(5), 0x3DD8A9DC) AS [UTF-16LE];
UNIQUEIDENTIFIER
类似于“它是什么”和“它如何存储”两者不同且不需要匹配。请记住,UUID / GUID不像int
或char
等基本数据类型,而更像具有定义格式的实体,就像JPG或MP3文件一样。有关UNIQUEIDENTIFIER
的更多讨论,请参见我在DBA.StackExcange上回答一个相关问题的答案(包括为什么它由Big Endian和Little Endian组合表示)。
BitConverter.GetBytes()
的输出为何具有误导性,而且不能与CONVERT(VARBINARY,
相类比。请再次阅读我的答案,如果您仍有疑问,请告诉我。谢谢。 - Solomon Rutzky