【问题标题】:What are the known ways to store a tree structure in a relational DB? [closed]在关系数据库中存储树结构的已知方法是什么? [关闭]
【发布时间】:2010-07-29 12:59:06
【问题描述】:

"put a FK to your parent" method,即每条记录都指向它的父级。
这是一个很难读取的操作,但很容易维护。

还有一个“目录结构键”方法:

0001.0000.0000.0000 main branch 1
0001.0001.0000.0000 child of main branch one
etc

这非常容易阅读,但很难维护。
其他方法及其优缺点是什么?

【问题讨论】:

  • 我们使用的是old-age方法,使用FK引用父级来存储分层数据,并且几乎很高兴。为了加载大量数据,我们进行 XML 查询并反序列化为对象。
  • 乍一看,树结构和 RDBM 是 horrible fit。如果我见过Structured Storage 的用例,就是这样。
  • +1 “可怕的适合”链接给出了如何使用 2 个结构和一些建议阅读的示例。
  • 请参阅 stackoverflow.com/questions/846201/… 了解嵌套集、键命名方案和其他将层次结构压缩为关系的方法。
  • @Constantin 这不是我在这里展示的第二种方式吗?

标签: mysql design-patterns tree relational-database


【解决方案1】:

一如既往:没有最佳解决方案。每个解决方案都使不同的事情变得更容易或更难。适合您的解决方案取决于您将进行最多的操作。

带有 parent-id 的朴素方法:

优点:

  • 易于实施

  • 轻松将大子树移动到另一个父级

  • 插入物很便宜

  • 在 SQL 中可直接访问的所需字段

缺点:

  • 检索整棵树是递归的,因此开销很大

  • 找到所有的父母也很昂贵(SQL 不知道递归......)

修改前序树遍历(保存起点和终点):

优点:

  • 检索整棵树既简单又便宜

  • 找到所有的父母很便宜

  • 在 SQL 中可直接访问的所需字段

  • 奖励:您也在其父节点中保存子节点的顺序

缺点:

  • 插入/更新可能会非常昂贵,因为您可能需要更新很多节点

在每个节点中保存路径:

优点:

  • 找到所有的父母很便宜

  • 检索整棵树很便宜

  • 插入很便宜

缺点:

  • 移动一棵树很昂贵

  • 根据您保存路径的方式,您将无法直接在 SQL 中使用它,因此如果您想更改它,您将始终需要获取并解析它。

闭包表

优点:

  • 易于实施

  • 找到所有的父母很便宜

  • 插入很便宜

  • 检索整棵树很便宜

缺点:

  • 需要一个额外的表

  • 与其他方法相比占用大量空间

  • 移动子树很昂贵

我更喜欢最后两种中的一种,具体取决于数据更改的频率。

另请参阅:http://media.pragprog.com/titles/bksqla/trees.pdf

【讨论】:

  • 我同意你的观点:根本没有最好的解决方案。无论如何,有几种不同的方法来表示树数据结构,并且有几种技术可以在关系模型中拟合这些表示。通常,我更喜欢区分两种情况:1. 读密集型和 2. 写密集型。根据具体情况,一种模型比另一种更适合:例如,如果写入密集,在非规范化表上写入大量指针可能会非常昂贵,从而降低性能。
  • 对于第三个选项,请在您最喜欢的搜索引擎中使用“Materialized Path”来了解更多信息。我花了一段时间才找到它的名字。第二个选项也称为“嵌套集”。
【解决方案2】:

修改前序树遍历

这是一种使用非递归函数(通常是单行 SQL)从数据库中检索树的方法,代价是更新起来有点棘手。

**

Sitepoint 文章Storing Hierarchical Data in a Database 的第 2 部分了解更多详情。

【讨论】:

  • 那篇文章很方便地忽略了树可能必须稍后更新,因此需要重新编号许多节点以保持一致。
  • 这篇文章完全没有忽略这一点。它在第 3 页明确指出您必须更新节点编号并提供 SQL 来执行此操作。
  • 应该注意的是,当您的读取次数远多于写入次数时,此模型非常好 - 如果您期望大量写入(例如,可能每 4 次读取 1 次写入)此模型可能会出现问题像简单的父 ID(以及更昂贵的读取)之类的东西可能更可取。
  • Modified Preorder Tree Traversal 是解决这个问题的好方法,以防不经常修改树结构。
【解决方案3】:

我会说存储分层数据结构的“黄金方式”是使用分层数据库。比如建屋局。这是一个可以很好地处理树的关系数据库。如果您想要更强大的功能,LDAP 可能会为您服务。

SQL 数据库不适合这种抽象拓扑。

【讨论】:

  • 我知道,我知道。我现在肯定会使用 MySql,所以我需要在我的约束范围内找到一个好的解决方案。
  • @msw 这是我在问题中提到的 FK 方法。
【解决方案4】:

我认为用关系数据库构建树形结构并不难。

但是,面向对象的数据库会更好地实现此目的。

使用面向对象的数据库:

parent has a set of child1  
child1 has a set of child2  
child2 has a set of child3  
...  
...

在面向对象的数据库中,您可以很容易地构建这种结构。

在关系数据库中,您必须维护父级的外键。

parent  
id  
name  

child1  
parent_fk  
id  
name 

child2  
parent_fk  
id  
name  

..

基本上,当您构建树结构时,您必须连接所有这些表,或者您可以遍历它们。

foreach(parent in parents){
   foreach(child1 in parent.child1s)
    foreach(child2 in child1.child2s)

...

【讨论】:

  • 以这种方式迭代数据库可能非常昂贵,主要是如果您必须从大树结构中仅检索子树。
猜你喜欢
  • 2013-02-01
  • 2016-08-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多