【发布时间】:2011-05-02 04:19:38
【问题描述】:
良好的概述
一般来说,您是在快速读取时间(例如,嵌套集)或快速写入时间(邻接列表)之间做出决定。通常,您最终会得到最适合您需求的以下选项的组合。以下提供了一些深入阅读:
- One more Nested Intervals vs. Adjacency List comparison:我发现的邻接列表、物化路径、嵌套集和嵌套区间的最佳比较。
- Models for hierarchical data:幻灯片很好地解释了权衡和示例用法
- Representing hierarchies in MySQL: 对嵌套集的概述非常好,尤其是
- Hierarchical data in RDBMSs:我见过的最全面和组织良好的一组链接,但解释的方式并不多
选项
我知道的和一般特征:
- 列:ID、ParentID
- 易于实施。
- 廉价的节点移动、插入和删除。
- 昂贵的寻找关卡、祖先和后代、路径
- 在支持它们的数据库中避免通过Common Table Expressions 进行 N+1
- 列:左、右
- 廉价的祖先,后代
- 由于易失编码,
O(n/2)移动、插入、删除非常昂贵
- 使用带有祖先、后代、深度的单独连接表(可选)
- 廉价的祖先和后代
- 插入、更新、删除的写入成本
O(log n)(子树的大小) - 规范化编码:适用于连接中的 RDBMS 统计信息和查询规划器
- 每个节点需要多行
- Lineage Column(又名Materialized Path,路径枚举)
- 列:血统(例如 /parent/child/grandchild/etc...)
- 通过前缀查询便宜的后代(例如
LEFT(lineage, #) = '/enumerated/path') - 插入、更新、删除的写入成本
O(log n)(子树的大小) - 非关系型:依赖数组数据类型或序列化字符串格式
- 类似于嵌套集,但使用实数/浮点数/十进制数,因此编码不是易失性的(廉价的移动/插入/删除)
- 存在实数/浮点数/十进制表示/精度问题
- Matrix encoding variant 为“免费”添加了祖先编码(物化路径),但增加了线性代数的技巧。
- 修改后的邻接列表,为每条记录添加一个级别和排名(例如排序)列。
- 迭代/分页成本低
- 昂贵的移动和删除
- 良好用途:线程讨论 - 论坛/博客 cmets
- 列:每个血统级别一个,指的是所有父级,直到根,从项目级别向下的级别设置为 NULL
- 便宜的祖先,后代,等级
- 便宜的插入、删除、移动叶子
- 内部节点的昂贵插入、删除、移动
- 层次结构深度的硬性限制
数据库特定说明
MySQL
甲骨文
- 使用CONNECT BY遍历邻接表
PostgreSQL
- ltree datatype 用于物化路径
SQL 服务器
- General summary
- 2008 提供了 HierarchyId 数据类型,似乎有助于使用沿袭列方法并扩展可表示的深度。
【问题讨论】:
-
根据slideshare.net/billkarwin/sql-antipatterns-strike-back 第77 页,
Closure Tables在易用性方面优于Adjacency List、Path Enumeration和Nested Sets(我也在猜测性能)。 -
我在这里错过了一个非常简单的版本:一个简单的 BLOB。如果您的层次结构只有几十个项目,则序列化的 id 树可能是最佳选择。
-
@Lothar:问题是一个社区 wiki,所以请随意使用。我在这方面的想法是,我只会使用那些支持某种 blob 结构的数据库,例如 XML 和稳定的查询语言,例如 XPATH。否则,除了在代码中而不是 SQL 中检索、反序列化和 munge 之外,我看不到查询的好方法。如果您确实遇到需要大量任意元素的问题,您可能最好使用像 Neo4J 这样的 Node 数据库,我已经使用并喜欢它,尽管它从未用于生产。
-
“General Summary”的 MSDN 链接不再显示该文章。它出现在 2008 年 9 月版的 MSDN 杂志中,您可以将其下载为 CHM 文件,或通过 Web 存档查看:web.archive.org/web/20080913041559/http://msdn.microsoft.com:80/…
标签: sql database tree relational-database hierarchical-data