好的概述
一般来说,您要在快速读取时间(例如,嵌套集)或快速写入时间(邻接列表)之间做出决定。通常,您最终会得到以下最适合您需要的选项组合。以下内容提供了一些深入阅读:
- 还有一个嵌套间隔与邻接列表比较:我找到的邻接列表、物化路径、嵌套集和嵌套间隔的最佳比较
- 分层数据模型:幻灯片,很好地解释了权衡和示例用法
- 在MySQL中表示层次结构:特别是嵌套集的非常好的概述
- RDBMS中的分层数据:我见过的最全面、组织最完善的链接集,但在解释方面不多
选项
我知道的和一般特征:
- 邻接列表:
- 列:ID,ParentID
- 易于实现
- 廉价节点移动、插入和删除
- 查找级别、祖先和;后代、道路
- 通过支持N+1的数据库中的公共表表达式避免N+1
- 嵌套集(又称修改的前序树遍历)
- 列:左、右
- 廉价的祖先、后代
- 非常昂贵的
O(n/2)由于易失性编码而移动、插入和删除
- 桥接表(又称闭合表/带触发器)
- 使用单独的联接表:祖先、后代、深度(可选)
- 廉价的祖先和后代
- 写入插入、更新和删除的成本
O(日志n)(子树大小) - 规范化编码:适用于RDBMS统计&;联接中的查询计划器
- 每个节点需要多行
- 沿袭列(又称物化路径、路径枚举)
- 列:血统(例如/父/子/孙/等)
- 通过前缀查询的廉价后代(例如
左(沿袭,#)='/enumerated/path') - 写入插入、更新和删除的成本
O(日志n)(子树大小) - 非关系:依赖于数组数据类型或序列化字符串格式
- 嵌套区间
- 与嵌套集类似,但使用实数/浮点数/十进制数,因此编码不会易变(便宜的移动/插入/删除)
- 存在实/浮/十进制表示/精度问题
- 矩阵编码变体为“添加祖先编码(具体化路径)”;免费;,但是线性代数又增加了一些技巧
- 平板
- 一种修改的邻接列表,在每条记录中添加一个级别和等级(如排序)列
- 重复/分页的成本很低
- 昂贵的移动和删除
- 好用:线程化讨论-论坛/博客评论
- 多个沿袭列
- 列:每个沿袭级别对应一列,表示到根的所有父级,从项目级别向下的级别设置为NULL
- 廉价的祖先、后代、等级
- 廉价的插入、删除、移动叶子
- 昂贵的内部节点插入、删除和移动
- 硬限制层次结构的深度
特定于数据库的注释
MySQL
- 将会话变量用于邻接列表
甲骨文
- 使用“连接方式”遍历邻接列表
PostgreSQL
- 物化路径的ltree数据类型
SQL Server
- 概述
- 2008提供的HierarchyId数据类型似乎有助于采用沿袭列方法并扩展可表示的深度
我最喜欢的答案是这个帖子的第一句话。使用邻接列表维护层次结构,并使用嵌套集查询层次结构
到目前为止的问题是,从邻接列表到嵌套集的转换方法非常慢,因为大多数人使用称为“推堆栈”的极端RBAR方法进行转换,一直被认为是一种昂贵的方法,可以通过邻接列表和嵌套集的出色性能实现维护的简单性。因此,大多数人最终不得不满足于其中一个,尤其是当节点数超过(比如)糟糕的100000个左右时。使用推栈方法可以花一整天的时间来完成MLME将被认为是百万字节层次结构的转换。
我想我会给Celko一点竞争的机会,想出一种方法,以似乎不可能的速度将邻接列表转换成嵌套集。下面是我的i5笔记本电脑上推堆栈方法的性能
1000个节点的持续时间=00:00:00:870
10000个节点的持续时间=00:01:01:783(比10个节点慢70倍)
100000个节点的持续时间=00:49:59:730(比100个节点慢3446倍)
1000000个节点的持续时间=’甚至没有尝试此操作’
这是新方法的持续时间(括号中有push-stack方法)
1000个节点的持续时间=00:00:00:053(与00:00:00:870相比)
10000个节点的持续时间=00:00:00:323(与00:01:01:783相比)
100000个节点的持续时间=00:00:03:867(与00:49:59:730相比)
1000000个节点的持续时间=00:00:54:283(相比之下,大约2天!!!)
是的,没错。在不到一分钟的时间内转换了100万个节点,在不到4秒内转换了100000个节点
您可以阅读有关新方法的信息,并从以下URL获取代码副本。
http://www.sqlservercentral.com/articles/Hierarchy/94040/
我还使用类似的方法开发了一个“预聚合”层次结构。传销商和制作物料清单的人对本文特别感兴趣。
http://www.sqlservercentral.com/articles/T-SQL/94570/
如果你确实来看看这两篇文章,请跳进“加入讨论”链接,让我知道你的想法