树形数据结构的数据库结构

175

如何在数据库中实现可定制的树形数据结构(即一个未知级别的树形结构)是最佳方式?

我曾经使用一个带有指向其自身的外键的表来完成此操作。

你能想到其他的实现方式吗?这种实现方式是否合理?


SQL Server(自2008年起)提供了hierarchyid数据类型 - BornToCode
5个回答

93
您提到的最常用的树形结构模型是邻接表(Adjacency List): https://blogs.msdn.microsoft.com/mvpawardprogram/2012/06/25/hierarchies-convert-adjacency-list-to-nested-sets。还有其他的模型,包括物化路径(materialized path)和嵌套集(nested sets): http://communities.bmc.com/communities/docs/DOC-9902。Joe Celko写了一本关于这个主题的书籍,从通用SQL方面来看是一个好的参考(在上述嵌套集文章链接中提到)。此外,Itzik Ben-Gann在他的书“Inside Microsoft SQL Server 2005: T-SQL Querying”中对最常见的选项进行了很好的概述。
选择模型时需要考虑以下几点:

1) 结构变化频率——树的实际结构变化频率如何。某些模型提供更好的结构更新特性。然而,将结构变化与其他数据变化分开是很重要的。例如,您可能希望对公司的组织图进行建模。有些人会使用邻接表来进行建模,使用员工ID将员工与其主管链接起来。这通常是一种次优的方法。一个经常更好的方法是将组织结构单独建模,并将员工作为该结构的属性进行维护。这样,当员工离开公司时,组织结构本身不需要改变,只需要更改与离开的员工的关联。

2) 树是否读写频繁——某些结构在读取结构时效果非常好,但在向结构写入时会产生额外的开销。

3) 你需要从结构中获取哪些类型的信息 - 一些结构优于提供特定类型的有关结构的信息。例如,查找节点及其所有子节点,查找节点及其所有父节点,查找符合某些条件的子节点计数等。您需要知道将需要哪些信息才能确定最适合您需求的结构。


嗨,我遇到了与问题陈述中完全相同的问题,并想向您询问有关上述主题的问题。考虑到第一个主题中的结构(组织结构化表格(而不是员工结构化表格),其中ParentId在同一表格中引用),我需要设置某个区域的老板是谁。我将直接将该特定区域的所有员工分配给它。您会把该特定区域的老板放在哪里?在同一区域内还是在上面的一个组中?我的方法是将他/她引用到上面的组中,我认为这样可以得到更好的结构。谢谢。 - Marcos Buarque
1
第一个链接似乎已经失效了。 - Jorge Leitao

66

请查看MySQL中管理分层数据。它讨论了在关系数据库中存储和管理分层(树形)数据的两种方法。

第一种方法是邻接列表模型,这正是您所描述的:具有指向表本身的外键。虽然这种方法很简单,但对于某些查询,如构建整个树状结构,它可能非常低效。

文章中讨论的第二种方法是嵌套集模型。 这个方法更有效和灵活。 详细的解释和示例查询请参考文章内容。


13

如果你必须使用关系型数据库来组织树形数据结构,那么Postgresql具有很酷的ltree模块,提供了表示存储在分层树状结构中的数据标签的数据类型。 你可以从那里获得想法。(更多信息请参见:http://www.postgresql.org/docs/9.0/static/ltree.html)

通常,LDAP用于组织以分层结构存储的记录。


2

我觉得有一个表与自己的外键是有意义的。

然后你可以使用SQL中的公共表表达式或Oracle中的connect by prior语句来构建你的树形结构。


我有一个日志表,其中包含一个LogID标识列和一个ParentLogID列,该列具有指向LogID列的FK。当事务中写入第一行日志记录时,我会获取SCOPE_IDENTITY()。所有其他日志记录都使用此值在ParentLogID列中写入。这对于分组归属于一起的行非常有用。这是唯一真正的方法来查看发生了什么,如果没有它,将会是多个事务的大杂烩日志行的混合体。 - KM.
@KM - 他说的是“有意义”,而不是“没意义”。 - John Rasch

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接