处理数据库中的层次结构数据

时间:2009-02-25 19:38:19

标签: sql hierarchical-data

我很想知道处理层次结构的最佳方法(最佳实践)是关于数据库设计的。这是我通常如何处理它们的一个小例子。

节点表

NodeId int PRIMARY KEY
NodeParentId int NULL
DisplaySeq int NOT NULL
Title nvarchar(255)

Ancestor Table

NodeId int
AncestorId int
Hops int

在NodeId上有索引,AncestorId,Hops

表格如下:

节点表

NodeId    NodeParentId    DisplaySeq    Title
1         NULL            1             'Root'
2         1               1             'Child 1'
3         1               2             'Child 2'
4         2               1             'Grandchild 1'
5         2               2             'Grandchild 2'

Ancestor Table

NodeId    AncestorId    Hops
1         NULL          0
1         1             0
2         1             1
2         2             0
3         1             1
3         3             0
4         1             2
4         2             1
4         4             0
5         1             2
5         2             1
5         5             0

通过这种设计,我发现对于大型层次结构,我可以通过连接AncestorId = target NodeId的Ancestor表来非常快速地获得层次结构的整个部分,如:

SELECT *
FROM Node n
INNER JOIN Ancestor a on a.NodeId=n.NodeId
WHERE a.AncestorId = @TargetNodeId

也可以轻松获得直接的孩子

SELECT *
FROM Node n
INNER JOIN Ancestor a on a.NodeId=n.NodeId
WHERE a.AncestorId = @TargetNodeId
AND Hops = 1

我很想知道您可能已经使用过哪种其他解决方案。根据我的经验,层次结构可能非常繁琐,任何优化检索的方法都非常重要。

6 个答案:

答案 0 :(得分:10)

有一些供应商特定的扩展可以做到这一点,但我最喜欢的db-neutral方式来自Joe Celko - 谷歌'Joe Celko树和层次结构'或者购买这本书:link text

这是一个非常聪明的基于集合的方式。易于查询层次结构。我添加了'parentID'字段,因为我问了'直接孩子'和'父母'问题,并加快了这些问题。但这是一种获得'祖先'或'descdent'查询的好方法。

答案 1 :(得分:6)

您可能还想查看“嵌套集”模式:

  

http://www.intelligententerprise.com/001020/celko.jhtml   (Broken Link)

或者你可以谷歌了解更多。

P.S。:诅咒,n8wrl,你输入的速度比我快!

答案 2 :(得分:4)

正如MarkusQ和n8wrl已经指出的那样,Joe Celko对此有一些好处。我只想补充说,有多种方法可以建立一个层次结构(Joe的书中包含了几个我相信的,而不仅仅是他认为是“最好的”)。您的最终决定有望考虑到您自己的特定需求。对其进行建模的一些不同方法对于写入密集型操作更好,而对于频繁或快速读取层次结构的其他方式则更好。请记住您的系统将使用它做什么。

答案 3 :(得分:2)

SQL Server 2008引入了hierarchyid data type

答案 4 :(得分:1)

在Oracle中,您可以使用CONNECT BY / START WITH来查询分层数据。 在SQL Server中,您可以使用以递归方式调用自身的存储过程。

答案 5 :(得分:1)