嵌套集合模型(Nested set model)介绍

原文链接:www.pilishen.com/posts/an-in…

此文档是 nestedset-无限分类正确姿势的扩展阅读

本文翻译自维基百科Nested set model

nested set model(嵌套集合模型)是一种在关系型数据库中表示nested sets(嵌套集合) 的特殊技术。[nested sets]通常指的是关系树或者层级关系。这个术语是由 Joe Celko清晰的提出来的,还有人使用不同的术语来描述这一技术。

诱因

该技术的出现解决了标准关系代数和关系演算以及基于它们的SQL操作不能直接在层次结构上表示所有期望操作的问题。层级可以用parent-child relation (父子关系)术语来表示 - Celko称之为 [adjacency list model],但是如果可以有任意的深度,这种模型不能用来展示类似的操作比如比较两个元素的层级或者确定一个元素是否位于另一个元素的子层级,当一个层级结构是固定的或者有固定的深度,这种操作必须通过每一层的 relational join (关系连接)来实现。但是这将很低效。这通常被称为物料清单问题。

通过切换到图形数据库,可以很容易地表达层次结构。另外在一些关系型数据库系统中存在并提供了这种关系模型的解决方案:

  • 支持专门的层级结构数据类型,比如SQL的hierarchical query facility(层级查询工具)。
  • 使用层级操作扩展关系型语言,比如 nested relational algebra。
  • 使用transitive closure扩展关系型语言,比如SQL的CONNECT语句;这可以在parent-child relation 使用但是执行起来比较低效。
  • 层级结构查询可以在支持循环且包裹关系的操作的语言中实现。比如 PL/SQL, T-SQL or a general-purpose programming language

当这些解决方案没被提供或不容易实现,就必须使用另一种方法

技术

嵌套集模型是根据树遍历来对节点进行编号,遍历会访问每个节点两次,按访问顺序分配数字,并在两次访问中都分配。这将为每个节点留下两个数字,它们作为节点两个属性存储。这使得查询变得高效:通过比较这些数字来获得层级结构关系。但是更新数据将需要给节点重新分配数字,因此变得低效。尽管很复杂但是可以通过不使用整数而是用有理数来改进更新速度。

例子

在衣服库存目录中,衣服可能会更加层级机构来分类:

处于层级结构顶端的Clothing分类包含所有的子类,因此它的左值和右值分别赋值为1和22,后面的值即这里的22是展现的所有节点总数的两倍。下一层级包含Men's和Women's两子类,各自包含必须被计算在内的层级。每一层的节点都根据它们包含的子层级来给左值和右值赋值。如上表所示。

表现

使用nested sets 将比使用一个遍历adjacency list的储存过程更快,对于天生缺乏递归的查询结构也是更快的选择。比如MySQL.但是递归SQL查询语句也能提供类似“迅速查询后代”的语句并且在其他深度搜索查询是更快,所以也是对于提供这一功能的数据库的更快选择。例如 PostgreSQL,[5]  Oracle,[6]  and Microsoft SQL Server.[7]

缺点

The use case for a dynamic endless database tree hierarchy is rare. The Nested Set model is appropriate where the tree element and one or two attributes are the only data, but is a poor choice when more complex relational data exists for the elements in the tree. Given an arbitrary starting depth for a category of 'Vehicles' and a child of 'Cars' with a child of 'Mercedes', a foreign key table relationship must be established unless the tree table is naively non-normalized. Attributes of a newly created tree item may not share all attributes with a parent, child or even a sibling. If a foreign key table is established for a table of 'Plants' attributes, no integrity is given to the child attribute data of 'Trees' and its child 'Oak'. Therefore, in each case of an item inserted into the tree, a foreign key table of the item's attributes must be created for all but the most trivial of use cases. If the tree isn't expected to change often, a properly normalized hierarchy of attribute tables can be created in the initial design of a system, leading to simpler, more portable SQL statements; specifically ones that don't require an arbitrary number of runtime, programmatically created or deleted tables for changes to the tree. For more complex systems, hierarchy can be developed through relational models rather than an implicit numeric tree structure. Depth of an item is simply another attribute rather than the basis for an entire DB architecture. As stated in SQL Antipatterns:[8]

Nested Sets is a clever solution – maybe too clever. It also fails to support referential integrity. It’s best used when you need to query a tree more frequently than you need to modify the tree.[9]

The model doesn't allow for multiple parent categories. For example, an 'Oak' could be a child of 'Tree-Type', but also 'Wood-Type'. An additional tagging or taxonomy has to be established to accommodate this, again leading to a design more complex than a straightforward fixed model. Nested sets are very slow for inserts because it requires updating left and right domain values for all records in the table after the insert. This can cause a lot of database stress as many rows are rewritten and indexes rebuilt. However, if it is possible to store a forest of small trees in table instead of a single big tree, the overhead may be significantly reduced, since only one small tree must be updated. The nested interval model does not suffer from this problem, but is more complex to implement, and is not as well known. It still suffers from the relational foreign-key table problem. The nested interval model stores the position of the nodes as rational numbers expressed as quotients (n/d). [1](//www.sigmod.org/publications/sigmod-record/0506/p47-article-tropashko.pdf)

变体

使用上面描述的nested set modal 在一些特定的树遍历操作上有性能限制。比如根据父节点查找直接子节点需要删选子树到一个指定的层级如下所示:

SELECT Child.Node, Child.Left, Child.Right
FROM Tree as Parent, Tree as Child
WHEREChild.Left BETWEEN Parent.Left AND Parent.RightAND NOT EXISTS (    -- No Middle NodeSELECT *FROM Tree as MidWHERE Mid.Left BETWEEN Parent.Left AND Parent.RightAND Child.Left BETWEEN Mid.Left AND Mid.RightAND Mid.Node NOT IN (Parent.Node AND Child.Node))AND Parent.Left = 1  -- Given Parent Node Left Index
复制代码

或者:

SELECT DISTINCT Child.Node, Child.Left, Child.Right
FROM Tree as Child, Tree as Parent 
WHERE Parent.Left < Child.Left AND Parent.Right > Child.Right  -- associate Child Nodes with ancestors
GROUP BY Child.Node, Child.Left, Child.Right
HAVING max(Parent.Left) = 1  -- Subset for those with the given Parent Node as the nearest ancestor复制代码

当查询不止一层深度的子节点的时候,查询将更加的复杂,为了突破限制和简化遍历树,在模型上增加一个额外的字段来维护树内节点的深度:

在这个模型中,找到指定父节点的紧跟直接子节点可以使用下面的SQL语句实现:

SELECT Child.Node, Child.Left, Child.Right
FROM Tree as Child, Tree as Parent
WHEREChild.Depth = Parent.Depth + 1AND Child.Left > Parent.LeftAND Child.Right < Parent.RightAND Parent.Left = 1  -- Given Parent Node Left Index
复制代码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/452883.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

互联网商业模式:增值还是减值?

网络可以为服务增值&#xff0c;这是人们的共识。不但是增值&#xff0c;而且是按照用户的平方增值&#xff0c;这是梅特卡夫定律说的。 我认为&#xff0c;网络也可以为服务减值&#xff0c;是按照服务提供商的数量的平方减值。如果按用户增值是网络的第一定律&#xff0c;这…

程序的链接方式

1 静态链接 2 装入时动态链接 3 运行时动态链接

Django中--自定义模型管理器类

BookInfo.objects.all()->objects是一个什么东西呢&#xff1f; 答&#xff1a;objects是models.Manger类的一个对象&#xff0c;是Django帮我自动生成的管理器对象&#xff0c;通过这个管理器可以实现对数据的查询。 自定义管理器之后Django不再帮我们生成默认的objects管…

字符驱动之按键(四:poll机制)

1 采用之前的中断按键法&#xff0c;程序会一直在read函数中死循环。2 使用了poll之后&#xff0c;在一段时间内如果有按键按下就会返回&#xff0c;如果没有按键按下等时间到再返回。3 4 应用程序的open,read,write,poll分别对应了驱动程序的open,read,write和poll。5…

第二章 API的理解和使用

2.1.1全局命令 Key * 查看所有键&#xff0c;(慎用&#xff0c;会把所有键都遍历一次并列出) Dbsize 查看键总数&#xff0c;不会遍历所有键&#xff0c;只是从内置函数中读取一个数 Exists [key] 检查键是否存在 Del [key] 删除键 Expire [key] [seconds] 设置键过期时间 Type…

java uuid 线程安全_java – 在多线程应用程序中生成相同的UUID

我使用UUID.randomUUID().toString()将一个唯一值附加到最终存储在数据库中的字符串,并对其具有唯一约束但是因为我的应用程序是多线程的,所以执行在UUID生成的同时发生,并且最终将相同的UUID附加到字符串并且持久性失败.有没有更好的方法来生成随机字符串,即故障安全方法.我尝…

社会生活、工作中的著名法则

社会生活中的著名法则(1)&#xff1a;马太效应 《新约 马太福音》中有这样一个故事&#xff0c;一个国王远行前&#xff0c;交给三个仆人每人一锭银子&#xff0c;吩咐他们&#xff1a;“你们去做生意&#xff0c;等我回来时&#xff0c;再来见我。”国王回来时&#xff0c;第一…

Django中--使用redis存储历史浏览记录

class UserInfoView(LoginRequiredMixin, View):用户中心-信息页def get(self, request):显示# Django会给request对象添加一个属性request.user# 如果用户未登录->user是AnonymousUser类的一个实例对象# 如果用户登录->user是User类的一个实例对象# request.user.is_aut…

3D虚拟试衣有望解决厘米级服装误差 网购服装不再蒙

还在担心网购服装对实际穿着效果没把握吗&#xff1f;随着京东App 6.6.3版本的更新&#xff0c;京东试试3D虚拟试衣功能正式上线&#xff0c;消费者可按照自己的身材比例创建专属的3D模型&#xff0c;而试穿效果则可以完全依照模型来展现。据了解&#xff0c;这个系统未来还将实…

关于idea修改当前使用的git账户的问题

1、问题描述&#xff1a; 由于前一段时间公司迁移git&#xff0c;就是将项目代码等迁移到另一个git服务器上&#xff0c;结果用idea从git上clone代码的时候发现没有指定仓库,如下提提示 2、排查原因&#xff1a; 开始怀疑是没有把自己加入到项目成员里面&#xff0c;经过检查是…

分页和分段的区别

1.页是信息的物理单位&#xff0c;分页是由于系统管理的需要。段是信息的逻辑单位&#xff0c;分段是为了满足用户的要求。 2.页的大小固定且由系统决定&#xff0c;段的长度不固定&#xff0c;决定于用户所编写的程序&#xff0c;通常由编译程序在对源程序紧进行编译 时&…

java 修饰_Java 修饰符

摘录自http://www.runoob.com/java/java-modifier-types.htmlJava 修饰符Java语言提供了很多修饰符&#xff0c;主要分为以下两类&#xff1a;访问修饰符非访问修饰符修饰符用来定义类、方法或者变量&#xff0c;通常放在语句的最前端。我们通过下面的例子来说明&#xff1a;pu…

内存分配,任意字节对齐

有这么一道题目&#xff0c;要求按任意字节对齐分配内存&#xff0c;接口&#xff1a;char * aligned_malloc(int size, int alignment)//size 为分配的内存大小&#xff0c;alignment对齐基数&#xff08;可以为任意数&#xff09;这个在gcc库函数里能找到源码&#xff0c;在f…

day16-Dom提交表单以及其他

一、前言 之前我们学习的是from提交表单&#xff0c;那个是html的提交表单方式&#xff0c;现在我们用dom来提交表单&#xff0c;还有一些其他的方式 二、dom提交表单 2.1、html提交表单 说明&#xff1a;form标签跟submit类型的input标签结合 <body><form id"f1…

分布式文件系统FastDFS

1. 什么是FastDFS FastDFS 是用 c 语言编写的一款开源的分布式文件系统。FastDFS 为互联网量身定制&#xff0c; 充分考虑了冗余备份、负载均衡、线性扩容等机制&#xff0c;并注重高可用、高性能等指标&#xff0c;使用 FastDFS 很容易搭建一套高性能的文件服务器集群提供文件…

html5 下拉刷新(pc+移动网页源码)

本文demo下载地址&#xff1a;http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId1071 本文实现在html5网页中使用下拉功能自动刷新显示更多内容, 使用jquery捕捉和处理相应的鼠标事件, 例如内容在顶部时&#xff0c;触发下拉事件后显示更多内容; 如内容在…

操作系统内存管理问题集锦

1. 可采用哪几种方式将程序装入内存?它们分别适用于何种场合? a. 首先由编译程序将用户源代码编译成若干目标模块&#xff0c;再由链接程序将编译后形成的目标模块和所需的-库函数链接在一起&#xff0c;组成一个装入模块&#xff0c;再由装入程序将装入模块装入内存&#x…

java同名变量在list中添加两次_快速解决List集合add元素,添加多个对象出现重复的问题...

首先我们在new 一个对象的时候&#xff0c;对象的id是唯一确定的&#xff1b;将对象add入list中时&#xff0c;放入list中的其实是对象的引用 &#xff1b;而每次循环只是简单的set 对象的属性&#xff0c;set新的属性值&#xff0c;而add进list中的对象还是同一个对象id&#…

python面试题总结(1)--语言特性

1. 谈谈对 Python 和其他语言的区别 答&#xff1a; Python 是一门强类型的可移植、可扩展、可嵌入的解释型编程语言&#xff0c;属于动态语言&#xff1b;其语法简洁优美、功能强大无比、应用领域非常广泛且具有强大完备的第三方库。 &#xff08;注&#xff1a;语言有无类型…

视频网站盈利模式与营销策划

在与数十家视频网站进行信息网络传播权交易过程中&#xff0c;在研究视频网站内容和盈利模式基础上&#xff0c;综合自己在传统媒体和新媒体领域十几年的策划和营销经验&#xff0c;我发现&#xff1a;视频网站的盈利模式其实早就形成多种体系&#xff0c;但是盈利之路艰难&…