基于前序遍历的无递归的树形结构的数据库表设计

本文介绍的方法基于多叉树的前序遍历序列,是所有数据库树结构存储方案中查询子树速度最快的方案。最早发表在这里"http://drinkjava2.iteye.com/blog/2353983",但那篇文章太啰嗦了,这是整理后的精简版,其实原理很简单,几句话就能说完。

目前常见的树形结构数据库存储方案有以下四种,但是都存在一定问题:
1)Adjacency List(邻接表):每个节点仅记录父节点主键。优点是简单,缺点是访问子树需要递归遍历,对数据库压力大(即使是支持递归SQL的数据库)。
2)Path Enumerations( 路径枚举):用一个字符串记录当前节点所在路径。优点是查询方便,缺点是占用空间大,查询需要使用like模糊方法,效率低,插入新记录时要手工更改此节点以下所有路径,维护不便。
3)Closure Table(闭包表):专门一张表维护Path,缺点是占用空间大,操作不直观。
4)Nested Sets (嵌套集):记录左值和右值,优点是查询子树无需递归,缺点是非常复杂、难操作。

本文介绍的基于树形结构的前序遍历序列方法,示意图如下:
[img]http://dl2.iteye.com/upload/attachment/0129/5437/028fbbed-b695-34ea-b6e9-87d79ba11681.png[/img]

如上图左边的树结构,映射在数据库里的结构见右图表格,注意整个表格是一个排好序的树结构的前序遍历序列,相同节点深度的排序以line为准。 表格的最后一行(或每个根节点)必须有一个END标记,level设为0,上表中的ID为主键,Level为树节点的深度。在以上基础上,只要一句SQL,就可以无递归查询出任意节点的所有子树节点, 比某些数据自带的基于递归原理的查询更高效。 假设节点的行号为X,level为Y,则查询整个子树的SQL为:
select * from tb where line>=X and line<(select min(line) from tb where line>X and level<=Y)
例如获取D节点及其所有子节点:
select * from tb where line>=7 and line< (select min(line) from tb where line>7 and level<=2)

它依据的原理很简单:按树结构的前序遍历序列存储的树结构,判断它的所有子结点,只要从这个节点开始往下划竖线,竖线右边的全是它的子节点,直到碰到竖线上或竖线左边出现非空值则终止,原理图如下:
[img]http://dl2.iteye.com/upload/attachment/0129/5429/815b0a6e-4bc1-384e-81c5-20bf6c96d3f8.jpg[/img]

这种方案的优点是查询高效,删除高效(只需要删除当前行即可,虽然会造成line字段的跳号,但是不影响使用),插入节点也很简单,只需要2行简单的SQL即可,例如要在line=9和line=10的两个节点之间插入一个新节点,则新节点行号应为10,原行号为10的将变为11, SQL操作为:
update tb2 set line=line+1 where line>=10; //把10以后的所有行号加1
insert into tb (line,id,level) values (10,'T',4); //执行插入新节点操作
虽然影响的行数非常多,但是理解和维护都非常简单。 如果担心插入操作对性能的影响,还可以将行号跳号设计(如按100000跳号),新的节点可以插入在两个节点的空号区中段(如果节点间存在空号区),这样可以很大程序上消除进行加1操作的概率。另外一个表只需要一个End标记,可以设为一个固定的非常大的数值(要大于所有line值)。

这种方案的缺点是当需要移动节点时,必须维护整张表的前序遍历排序顺序,必要时要进行整张表或子树的重排序, 这是一个很耗时的工作(其它三种方案Path Enumerations/Closure Table/Nested Sets也有这个缺点),这是不可避免的,是以始终维护一个索引为代价换取查询性能的提高。因此它最适合只有增删查操作,但是很少有移动节点的场合。

总结:这种方案最适合的场合是树的深度很深(可以超过上百万),不经常移动节点、对查询速度要求极高的场合(因为无递归)。

本文实际上可以抽象成一种利用前序遍历给多叉树建查询索引的方案,即使在没有数据库存在的情况下,也是有可能在程序中应用到这种方案的,只要将SQL中的查询功能改成手工进行数组遍历即可。
另外,数据库开发者也可以考虑,对于邻接表模式(即只有id和pid两个关键字段)存储的树结构, 可以用这种方法创建一个内部索引,将level和line作为数据库表的隐藏字段,这样用户就可以不用手工维护level、line以及维护前序遍历排序这些与业务无关的操作,这才是最人性化的使用方式。
采用左右值编码来存储无限分级树形结构的数据库表设计    之前我介绍过一种按位数编码保存树形结构数据的表设计方法,详情见:  浅谈数据库设计技巧(上)   该设计方案的优点是:只用一条查询语句即可得到某个根节点及其所有子孙节点的先序遍历。由于消除了递归,在数据记录量较大时,可以大大提高列表效率。但是,这种编码方案由于层信息位数的限制,限制了每层能所允许的最大子节点数量及最大层数。同时,在添加新节点的时候必须先计算新节点的位置是否超过最大限制。 阅读详情

相关推荐

非常实用的树形菜单,有数据库表

java实现的非常实用的树形菜单,有数据库表

mysql分层数据管理--Managing Hierarchical Data in MySQL(译文)

原文地址:http://dev.mysql.com/tech-resources/articles/hierarchical-data.htmlIntroduction大多数用户都曾在数据库中处理过分层数据(hierarchical data),认为分层数据的管理不是关系数据库的目的。之所以这么认为,是因为关系数据库中的表没有层次关系,只是简单的平面化的列表;而分层数据具有父-子关系,显然关系数据...

kukuwuwu的专栏 327

动态树形菜单数据库表设计

这是一篇pdf格式的论文。很详细地图文并茂地讲解了树形菜单的设计。并分析了常规设计方式的不足。以冗余数据的方式设计了高效的树形菜单表。

SQLAlchemy MPTT:实现高效的数据库树形结构管理

SQLAlchemy MPTT:实现高效的数据库树形结构管理 项目介绍 SQLAlchemy MPTT(????GitHub)是专为Python开发者设计的一个扩展,它允许在使用SQLAlchemy作为ORM时实现修改后的前序遍历树遍历(Modified Preorder Tree Traversal,简称MPTT)。此库类似Django中的MPTT,极大地简化了在关系型数据库中表示和操作嵌套集合(如树...

gitblog_00585的博客 535

告别仿真失败!用Sigrity 2022 SystemSI搞定DDR4信号质量仿真的保姆级流程

本文详细介绍了如何使用Sigrity 2022 SystemSI工具进行DDR4信号完整性仿真,提供了一套避免仿真失败、提高仿真精度和加速仿真流程的保姆级方法。从模型验证、设计数据预处理到拓扑构建和参数提取,再到高级调试技巧和仿真加速方案,帮助硬件工程师系统性地解决DDR4信号质量仿真中的常见问题。

weixin_42537499的博客 343

CAPL实战:从零构建HEX文件解析器,赋能UDS刷写

本文详细介绍了如何使用CAPL从零构建HEX文件解析器,以支持UDS刷写操作。通过解析HEX文件格式、设计状态机、优化数据结构与算法,实现高效准确的固件数据处理,并提供了与UDS刷写流程对接的工程化实践建议。

weixin_28726391的博客 444

mysql查询树形结构数据库设计_基于前序遍历的无递归的树形结构的数据库表设计...

基于前序遍历的无递归的树形结构的数据库表设计声明:本文转载自https://my.oschina.net/drinkjava2/blog/1818631,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。本文介绍的方法基于多叉树的前序遍历序列,是所有数据库树结构存储方案中查询子树速度最快的方案。最早发表在这里"http://drinkjava2.iteye.com/...

weixin_36319281的博客 591

SAP MRKO与MIRO的对比分析:为何寄售结算需要定制开发?

本文深入分析了SAP系统中MRKO与MIRO在寄售结算中的功能差异,揭示了标准MRKO在财务控制和业务流程上的局限性。通过定制开发实践,如BAdI增强和界面优化,企业可显著提升结算效率与准确性。文章还探讨了未来SAP S/4HANA在寄售结算中的智能化趋势,为相关企业提供技术参考。

weixin_29300241的博客 426

数据结构--知识点16--搜索算法(二叉树)

文章目录一、树的概念1、特点2、树的术语3、树的种类4、树的存储与表示5、常见的树的应用场景二、二叉树1、概念2、性质 一、树的概念 树是一种抽象数据类型(ADT)或是视作这种抽象数据类型的数据结构 1、特点 每个节点有零个或多个子节点 没有父节点的节点称为根节点 每一个非根节点有且只有一个父节点 除了根节点外,每个子节点可以分为**多个不相交(因为都只有一个父节点)**的子树 2、树的术语 节点的度:一个节点含有的子树的个数称为该节点的度 树的度:一棵树中,最大的节点的度称为树的度 叶节点或终端节点

ANingL的博客 3543

TPL5010硬件看门狗电路

在做一些采集频率很低的产品的时候,会考虑电池供电,比如表、电气表等,为了控制功耗,往往会在设备不需要工作的时候让它进入低功耗模式。为了设备的稳定性,避免死机后无法恢复,必须配置看门狗,一般的看门狗芯片,喂狗间隔时间是几秒钟。这样在喂狗和低功耗之间就产生了一个矛盾,频繁的喂狗就需要频繁的醒过来,这样功耗就很难做到很低。这颗看门狗芯片,特别适合上面的应用。2小时的间隔意味着主控芯片每2小时醒过来喂狗一次即可,而在2.5V供电的情况下,功耗仅仅35nA,几乎可以忽略不计。

zxm8513优快云博客 3309

点云配准3:3d-ndt算法在pcl上的实现以及参数设置

3d-ndt算法在pcl上的使用方法以及参数设置

诺有缸的高飞鸟的博客 7893

带有层号的先根遍历树存储基于plsql的代码实现

本文介绍了带有层号的先根遍历树存储基于plsql的代码实现,本文中涉及的代码编写于2014年3月。另外,本文提供了测试表创建语句以及插入节点、获取直接子节点、获取自身及子孙节点、获取根到指定节点的路径、删除节点等方法的存储过程源码与测试样例。

李明子的专栏 2436

机器人动力学仿真软件:Webots_(14).机器人声音仿真

Webots 中的声音仿真主要通过Sound和两种节点来实现。Sound节点用于播放预定义的音频文件,而节点则允许在仿真过程中动态生成和播放声音。这些节点可以用于模拟机器人的语音输出、报警声、环境噪音等。以下是一个示例,展示如何在控制器代码中播放预定义的声音。// 控制器代码(.c) # include <webots/robot.h> # include <webots/sound.h> # define TIME_STEP 64 const char * sound_name = "sound";

kkchenjj的博客 1312

利用“海底捞算法”在MongoDB中优雅地存储一棵树

目前常见的树形结构数据库存储方案有以下四种,但是在处理无限深度、海量数据的树结构时,都存在一些问题: 1)Adjacency List(邻接表):每个节点仅记录父节点主键。优点是简单,缺点是访问子树需要递归遍历,对数据库压力大(即使是支持递归SQL的数据库)。 2)Path Enumerations( 路径枚举):用一个字符串记录当前节点所在路径。优点是查询方便,缺点是占用空间大,查询需要使用li...

weixin_30394669的博客 455

面向 OData V4 的 Fiori elements 为何强制使用 draft、它到底是什么、以及是否能关闭

本文深入解析了SAP Fiori elements中draft handling的核心机制与必要性。关键点包括:1)draft机制通过中间版本实现复杂编辑的安全恢复与并发控制;2)Fiori elements for OData V4强制要求draft-enabled服务支持事务编辑;3)非draft服务仅适用于只读场景;4)替代方案需承担完全自定义开发的成本。文章基于SAP官方文档,系统阐述了draft在事务型应用中的基础性作用,为架构决策提供了明确指导。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 268

CE电流法测试中的dBμV负值解析

传导发射(CE)电流法测试中出现的dBμV负值现象表明被测设备干扰电平低于1μV参考基准。这源于对数计算特性(小于1μV的电压转换后为负值)、设备优良的EMC设计(如滤波效果显著)及测试环境的影响(LISN隔离、屏蔽室低噪声)。负值虽不代表实际负电压,但反映干扰水平优于标准限值,为系统集成预留电磁裕度。工程应用中需结合设备灵敏度、环境背景噪声等因素综合分析,避免误判,这类数据可用于评估EMI设计冗余度。

硬核科技 298

海底捞java开发_利用“海底捞算法”在MongoDB中优雅地存储一棵树

目前常见的树形结构数据库存储方案有以下四种,但是在处理无限深度、海量数据的树结构时,都存在一些问题:1)Adjacency List(邻接表):每个节点仅记录父节点主键。优点是简单,缺点是访问子树需要递归遍历,对数据库压力大(即使是支持递归SQL的数据库)。2)Path Enumerations( 路径枚举):用一个字符串记录当前节点所在路径。优点是查询方便,缺点是占用空间大,查询需要使用like...

weixin_39623350的博客 288

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

树形结构的数据库表Schema设计

树形结构的数据库表Schema设计:一种基于左、右值编码前序遍历的树形结构数据库表Schema设计方案,消除了频繁的“递归”操作,提升了树形结构查询效率~

愤怒的小狐狸----博客专栏 9万+

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

数据结构之树的多种遍历方式(前序遍历,后序遍历,中序遍历)

主要是记录一下书的多种遍历方式: 第一种: 前序遍历 第二种: 后序遍历 第三种: 中序遍历 第四种: 广度优先搜索 - 所谓的广度优先搜索,指的是 第五种: 深度优先搜索

冷萃美式的博客 2087

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

数据结构之二叉树的前序遍历、中序遍历、后序遍历、层序遍历

最近也是在准备笔试,由于没有系统的学过数据结构,所以每次在考到二叉树的遍历的时候都是直接跪,次数多了也就怒了,前些天也是准备论文没时间整这些,现在提交了,算是稍微轻松点了,所以花了半天的时间来学了下二叉树。现在记下来,以便后序查阅。 一、二叉树的遍历概念     1.  二叉树的遍历是指从根结点触发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次且仅被访问一次。 (1). 前(

gongwq的博客 5万+

数据结构之树(三)树的前序遍历,终须遍历,后序遍历

1、前序遍历      规则是,若二叉树为空,则空操作反馈,否则,先访问根结点,然后前序遍历左子树,再前序遍历右子树。      算法结构代码:   2、中序遍历        规则是,若二叉树为空,则空操作反馈,否则,先从根结点开始(这里并不是访问),中序遍历根结点的左子树,然后是访问根结点,最后中序遍历右子树,      算法结构代码: 3、后序遍历    ...

yuewei19的专栏 1538

树的三种遍历:前序,中序,后序

总体思路: 排序 定位一个元素,利用双指针游走其他元素 符合则添入答案列表,否则略过 特殊情况及细节问题 重复的元素需要略去,利用while循环和if判断语句。 若三者和小于0,则挪动指针左值右移,保持指针右值只能右移,这里注意,如果 ...

qq_45804132的博客 1万+

多层级树形结构数据库存储方式

要做一个多层级树形结构数据,后端数据如何存储,以怎样的形式给前端呢 方法1:Adjacency List存储相邻关系 id, parent_id以邻接表(Adjacency List)的形式进行存储在一张表中 这种方式在关系存储比较简单,查询的时候比较复杂。 比如查询部门下的所有子部门信息,因为表中只记录的上下级的部门及其子部门信息。需要遍历表中的信息 这有两种方式。 方式1:...

weixin_30871701的博客 2953

逻辑数据库设计 - 单纯的树(递归关系数据)

逻辑数据库设计 - 单纯的树(递归关系数据)   相信有过开发经验的朋友都曾碰到过这样一个需求。假设你正在为一个新闻网站开发一个评论功能,读者可以评论原文甚至相互回复。   这个需求并不简单,相互回复会导致无限多的分支,无限多的祖先-后代关系。这是一种典型的递归关...

ajwqb06628的专栏 2246

数据结构基础15:二叉树的前序、中序和后序遍历

前言:到目前为止,我们已经介绍了线性数据结构和表数据机构(哈希表)。这些数据机构一般都不适合表示具有层级结构的数据。在层次化的元素之间有祖先—后代、上级—下属、整体—部分以及其他类似的关系。 一、树的介绍 1、树的定义: 树状图是一种数据结构,它是由n(n&gt;=0)个结点组成一个具有层次关系的有穷集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。n=0...

何哥的博客 4708
上一篇: 历时一年开发,Java持久层工具jSqlBox第一个正式版本发布
Drinkjava2
博客等级 码龄11年 9粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值