【发布时间】:2012-01-02 00:41:40
【问题描述】:
一段时间以来,我一直在思考如何最好地处理 SQL 中的层次结构。由于邻接列表的局限性和 MPTT/嵌套集的复杂性,我开始考虑简单地将关键路径存储为简单的node_key/node_key/... 字符串。我决定整理一下这三种技术的优缺点:
创建/删除/移动节点所需的调用次数:
- 邻接 = 1
- MPTT = 3
- Path = 1(将旧节点路径替换为包含该路径的所有节点的新节点路径)
获取树所需的调用次数:
- 邻接 = [子级数]
- MPTT = 1
- 路径 = 1
获取节点/祖先路径所需的调用次数:
- 邻接 = [超层数]
- MPTT = 1
- 路径 = 0
获取子节点数所需的调用次数:
- 邻接 = [子级数]
- MPTT = 0(可以从右/左值计算)
- 路径 = 1
获取节点深度所需的调用次数:
- 邻接 = [超层数]
- MPTT = 1
- 路径 = 0
需要的数据库字段:
- 邻接 = 1(父)
- MPTT = 3(父、右、左)
- 路径 = 1(路径)
结论
存储路径技术在除一个以外的每个用例中都使用与其他技术相同或更少的调用。通过这种分析,存储路径显然是赢家。更不用说,它实现起来要简单得多,易于阅读等。
所以问题是,存储路径不应该被视为比 MPTT 更强大的技术吗?为什么存储路径不是一种更常用的技术,为什么不在给定实例中通过 MPTT 使用它们?
另外,如果您认为此分析不完整,请告诉我。
更新:
以下是 MPTT 开箱即用的至少 2 件存储路径解决方案无法做到的事情:
- 无需任何额外查询即可计算每个节点的子节点计数(如上所述)。
- 对给定级别的节点施加命令。其他解决方案是无序的。
【问题讨论】:
-
在邻接模型中需要 [sub-levels] 的调用实际上是不正确的。你可以这样做:
SELECT * FROM adjacency a /* for($number_of_levels_required.. $prevname = $level > 1 ? 'a'+$level-1 : 'a'; */ INNER JOIN adjacency a/*$level*/ ON a/*$level*/.parent_id = /*$prevname*/.id /* endfor*/ -
如何在路径中分别查询孩子和所有后代。我认为对 Path 的最大缺点是
referential integrity,正如 Bill Karwin 在他的回答中提到的那样。 -
@buffer - “如何查询孩子和所有后代”?这是使用路径最简单的部分:
SELECT * FROM items WHERE path LIKE 'my/child/path%';。是的,参照完整性会受到影响,但代价是查询效率更高。
标签: sql data-modeling hierarchical-data adjacency-list mptt