【问题标题】:How is HierarchyId stored in SQL Server?HierarchyId 如何存储在 SQL Server 中?
【发布时间】:2022-01-05 15:36:51
【问题描述】:

我有一个hierarchyid,其值为“/1/”。当我将它插入 SQL 数据库时,它存储为 0x58。

这是我的桌子:

CREATE TABLE [dbo].[Category](
    [CategoryId] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](max) NULL,
    [HierarchyDescription] [hierarchyid] NULL,
 CONSTRAINT [PK_Category] PRIMARY KEY CLUSTERED 
(
    [CategoryId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

这就是我的做法:

INSERT INTO [dbo].[Category] ([Name] ,[HierarchyDescription])
VALUES ('CAT1', '/1/');

0x58这个值是怎么得到的?

我尝试在 C# 中这样做

Encoding.ASCII.GetBytes("/1/");

我得到了十六进制值 0x2F312F (47 49 47)。

【问题讨论】:

  • 真的select cast(0x58 as [hierarchyid]) bh/1/。从未见过它记录在案,但c# example
  • 您要解决什么问题?也就是说,一旦您知道不透明数据类型的内部结构是什么,您可以做什么?
  • 基本上我想在 c# 中创建一个字节[],它可以作为 HierarchyId 存储在 SQL Server 中

标签: sql sql-server hierarchyid


【解决方案1】:

HierarchyId is documented 非常紧凑

表示一个节点所需的平均位数 具有 n 个节点的树取决于平均扇出(平均 节点的子节点)。对于小扇出(0-7),大小约为 6*logAn 位,其中 A 是平均扇出。一个节点 100,000 人的组织层次结构,平均扇出数为 6 级别大约需要 38 位。这四舍五入到 40 位或 5 个字节, 用于存储。

因此很明显,它可以在一个字节中容纳多个级别。

内部格式没有记录,但有人has previously investigated this(当我查看原始页面时,由于原始页面没有加载,所以返回机器链接)。

免责声明:来源本身是非权威的,只是从价值检查中推断出来的,我可能在下面引入了进一步的错误!

下面给出了一些相当简单的例子

WITH HierarchyIdStrings(path) As
(
SELECT '/'  UNION ALL
SELECT '/0/'  UNION ALL
SELECT '/1/'  UNION ALL
SELECT '/1/1/'  UNION ALL
SELECT '/1.1/'  UNION ALL
SELECT '/2/'    UNION ALL
SELECT '/98/'  
)
SELECT HierarchyId::Parse(path) AS HierarchyId, path, 
bin,
trimmed_bin = LEFT(bin, 1 + LEN(bin) - CHARINDEX('1', REVERSE(bin)))
FROM HierarchyIdStrings
CROSS APPLY(SELECT CONVERT(VARCHAR(1784), CAST(HierarchyId::Parse(path) AS VARBINARY(892)), 2)) V1(hex)
CROSS APPLY (SELECT 
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(
hex,
 '0', '0000'),'1', '0001'),'2', '0010'),'3', '0011'),
 '4', '0100'),'5', '0101'),'6', '0110'),'7', '0111'),
 '8', '1000'),'9', '1001'),'A', '1010'),'B', '1011'),
 'C', '1100'),'D', '1101'),'E', '1110'),'F', '1111') ) V2(bin)
 ORDER BY HierarchyId

结果

+-------------+-------+--------------------------+--------------------+
| HierarchyId | path  |           bin            |    trimmed_bin     |
+-------------+-------+--------------------------+--------------------+
| 0x          | /     |                          |                    |
| 0x48        | /0/   |                 01001000 |              01001 |
| 0x58        | /1/   |                 01011000 |              01011 |
| 0x5AC0      | /1/1/ |         0101101011000000 |         0101101011 |
| 0x62C0      | /1.1/ |         0110001011000000 |         0110001011 |
| 0x68        | /2/   |                 01101000 |              01101 |
| 0xE02540    | /98/  | 111000000010010101000000 | 111000000010010101 |
+-------------+-------+--------------------------+--------------------+

0x58 的二进制表示是01011000,但尾随零应该被忽略,所以我们只需要关心 5 位。 01011.

链接的文章假设初始前缀 01 是为组件 /0/ ... /3/ 保留的,因此它知道它只需要为该组件再读取三个位。接下来的两位是值本身,最后一位是1,因为这不是虚线组件。

/1/1/ 的表示只是将其中两个连接在一起。

1.1 的表示将1 添加到01011 以得到01100,然后将01011 连接到其末尾。

/98/ 更复杂。这给出了111000000010010101 的位串。

链接文章指出/80//1103/ 的范围将具有前缀1110 并采用1110aaa0zzz0y1xxx1 形式

  • aaa = 000(十进制0
  • zzz = 001(十进制1
  • y = 0(十进制0
  • xxx = 010(十进制2

1x + 8y + 16z + 80 = 2 + 0 + 16 + 80 = 98

组件也有可能是负数。如果对此感兴趣,请参阅链接文章!

【讨论】:

  • 我喜欢你的回答,因为它解释了它是如何工作的,我实际上所做的是使用 MemoryStream 来获取字节 []。我想您描述了 MemoryStream 如何处理具有 HierarchyId 格式的字符串
  • 是的 Microsoft.SqlServer.Types 程序集知道二进制格式——我假设你正在使用它。但这并不能回答您在询问“HierachyId 如何存储在 SQL Server 中?”时提出的问题。并在 SqlHierarchyId 类上调用一个方法并不能回答这个问题。它仍然使格式成为一个谜
  • 是的,你是对的,我忘了我是从 HierarchyId 调用 Write,我认为这只是将字符串写入 BinaryWriter 的通用写入。我的目标是重现 C# 中的存储值
【解决方案2】:

我通过以下方法解决了,可能有更好的方法

hierarchyValue = "/1/";
MemoryStream memStream = new MemoryStream();
BinaryWriter binWriter = new BinaryWriter(memStream);
hierarchyValue.Write(binWriter);
byte[] propertyValue = memStream.ToArray();

HierarchyId 存储在数据库中的值为propertyValue

【讨论】:

    猜你喜欢
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    • 2013-08-05
    相关资源
    最近更新 更多