gpt4 book ai didi

sql-server - 为什么 SQL Server 是 Big Endian?

转载 作者:行者123 更新时间:2023-12-03 15:00:04 27 4
gpt4 key购买 nike

据我所知,所有 Windows 版本和 .NET 都是小端。那么为什么要背离 Microsoft 的 SQL Server 规范呢?

我所说的“SQL Server is big endian”是这样的:

SELECT CONVERT(VARBINARY, 255);

给出:

0x000000FF

并不是

0xFF000000

.NET 的 BitConverter.GetBytes() 之类的方法。我猜 SQL Server 可能会在内部将数字存储为小端,然后 CONVERT 只是出于某种原因将其切换。但无论哪种方式,为什么呢?

编辑:

刚注意到这个...

DECLARE @q UNIQUEIDENTIFIER = '01234567-89ab-cdef-0123-456789abcdef';
SELECT @q;
SELECT CONVERT(VARBINARY, @q);

给我:

01234567-89AB-CDEF-0123-456789ABCDEF

0x67452301AB89EFCD0123456789ABCDEF

有没有搞错?

最佳答案

是的:Windows 和 .NET 是 Little Endian。

那么为什么 SQL Server 是 Big Endian?简单:这不是;-)。 Collation and Unicode Support 的 MSDN 页面(在 SQL Server 中)甚至指出:

Because the Intel platform is a little endian architecture, Unicode code characters are always stored byte-swapped.



那么为什么在转换 Int 值 255 时会得到 Big Endian 二进制值呢?这就是困惑的地方。这个问题是有缺陷的,因为它基于一个错误的前提:您应该看到转换后的值中反射(reflect)的硬件和/或软件的字节序。但你为什么要这样做?字节序会影响值的内部表示,以及它的存储方式。但它不会改变事物本身。您可以转换 DATETIMEINT你会看到一个整数。但是,如果您将该 Integer 保存在 INT 字段中,它将以相反的顺序存储为 4 个字节,因为这是一个 Little Endian 系统。但这与您从系统请求返回该值并显示给您时所看到的内容无关。

例如,运行以下命令查看转换 INT 301 的值到 BINARY(2)结果 0x012D ,因为 0x012D = 301,只是十六进制。所以转换 0x012D返回 INT返回 301 ,正如预期的那样。如果原始的 Int 到 Binary 转换给你 0x2D01,那么,这并不等于 301。

SELECT CONVERT(BINARY(2), 301), CONVERT(INT, 0x012D)
-- 0x012D, 301

但是,如果您创建一个带有 INT 的表列,并在该列中插入值“301”,然后使用 DBCC PAGE要查看磁盘上存在的数据页,您将按所示顺序看到以下十六进制数字:

2D 01 00 00

此外,为了解决支持问题前提的一些证据:

是的,在做 BitConverter.ToString(BitConverter.GetBytes(255))在 .NET 中将返回:

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 之间转换时,可以看到 SQL Server 是 Little Endian 的进一步证据。和 NVARCHAR .自 NVARCHAR是 16 位(即 2 字节)编码,我们可以看到字节顺序,因为字符没有数字等价物(与 256 -> 0x0100 示例不同),因此实际上没有其他可显示的(显示代码点值是由于补充字符而不是一个选项)。

正如您在下面看到的,拉丁大写字母 A ,其代码点为 U+0041(在数字上与 65 相同)转换为 VARBINARY 0x4100 的值,因为这是该字符的 UTF-16 Little Endian 编码值:
SELECT CONVERT(VARBINARY(10), N'A'), -- 0x4100
CONVERT(NVARCHAR(5), 0x4100), -- A
CONVERT(INT, 0x4100), -- 16640
UNICODE(N'A'), -- 65
CONVERT(VARBINARY(8), 65); -- 0x00000041

SELECT CONVERT(VARBINARY(10), N'ᄀ'), -- 0x0011
CONVERT(NVARCHAR(5), 0x0011), -- ᄀ
CONVERT(INT, 0x0011), -- 17
UNICODE(N'ᄀ'), -- 4352
CONVERT(VARBINARY(8), 4352); -- 0x00001100

此外,使用代理对“D83D + DCA9”( NCHAR 函数允许)可以看到“ Pile of Poo”表情符号(代码点 U+01F4A9),或者您可以注入(inject) UTF-16 小端字节序列:
SELECT NCHAR(0xD83D) + NCHAR(0xDCA9) AS [SurrogatePair],
CONVERT(NVARCHAR(5), 0x3DD8A9DC) AS [UTF-16LE];
-- 💩 💩
UNIQUEIDENTIFIER相似之处在于“它是什么”和“它是如何存储的”是两个不同的东西,它们不需要匹配。请记住,UUID/GUID 不是像 int 这样的基本数据类型。或 char ,但更像是一个具有定义格式的实体,就像 JPG 或 MP3 文件一样。更多关于 UNIQUEIDENTIFIER的讨论s 在我对 related question 的回答中关于 DBA.StackExcange(包括为什么它由 Big Endian 和 Little Endian 的组合表示)。

关于sql-server - 为什么 SQL Server 是 Big Endian?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21793348/

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