几种数据库中保存树的常见存储结构

在数据库中存储树时,常见的存储结构有以下几种:

常见存储结构

邻接列表

每个节点都有一个指向其父节点(pid)的引用。这种方法简单直观,也是最容易理解和常用的,但在获取整棵树或子树时可能需要多次查询。

存储结构

一般表结构如下:

CREATE TABLE tree (id INT PRIMARY KEY,pid INT,name VARCHAR(100),FOREIGN KEY (pid) REFERENCES nodes(id)
);

示例数据如下:

idpidname
1NULLroot
21A
31B
41C
52A-1
62A-2
72A-3

表示的树如下:

  • root
    • A
      • A-1
      • A-2
      • A-3
    • B
    • C

需要注意
pid树的查询和删除操作涉及到的递归操作,无法通过优化SQL解决,必须通过程序递归实现,这也意味着,在复杂树查询和操作时,需要在客户端与数据库之间频繁传输数据,效率较低。

优缺点

邻接列表模型,有明也简称为pid树,是最简单和常见的树结构存储模型。

  • 查询效率低

当需要以下查询时,一般需要进行递归查询,效率较低:

- 查询整棵树或子树
- 查询某个节点的所有后代
- 查询某个节点的祖先节点
  • 删除节点效率低

同样的,当我们要删除一个节点时,也需要递归删除其所有子节点,效率较低。

比如我们要删除节点A(id=100),只执行DELETE tree WHERE id=100 AND pid=100是不够的,因为A可能还存在多级后代节点,因此还需要递归删除其所有子节点,效率比较低下。

  • 无序树

树节点的之间的无序的,为此我们需要额外的字段来维护节点之间的顺序。
因此,在实际使用需要为表结构添加一个order字段,用来代表同一层级内节点的顺序,从而使得树变成有序树

idpidordername
1NULL1root
211A
312B
413C
521A-1
622A-2
723A-3

然后,我们通过select * from tree where pid=1 order by order来查询A的所有有序子节点集。

问题是,如果整棵树是有序的呢?

如果整棵树是有序的,则order字段必须是扩展到全树,如下:

idpidordername
1NULL1root
212A
317B
418C
524A-1
625A-2
726A-3

这样,我们就可以通过select * from tree order by order来查询整棵树的有序节点集。

但是问题来了,如果我们要调整树结构,比如将节点A移动到节点B下,那么我们就需要调整order字段,这样会导致大量的数据更新,效率较低。同时也无法避免order字段的唯一性问题,因此order字段的值必须是唯一的,这也增加了调整树结构的难度。

更糟糕的是, 始终无法避免递归调用更新的问题。

所以pid树的要实现完全的有序树是比较麻烦的。

  • 更新树结构

pid树需要调整树结构时效率是比较高的。

比如将节点A移动到节点B下 ,只需要将节点Apid修改为Bid即可。

但是由于其是无序树,所以如果要将节点A移动为节点B的下一个兄弟节点,则比较麻烦,需要额外的处理。

路径枚举

每个节点都保存了从根节点到自己的路径。这种方法可以方便地查询子树,但在插入或删除节点时需要更新大量数据。

存储结构
CREATE TABLE nodes (id INT PRIMARY KEY,path VARCHAR(255),name VARCHAR(100)
);

示例数据如下:

idpathname
1/rootroot
2/root/AA
3/root/BB
4/root/CC
5/root/A/A-1A-1
6/root/A/A-2A-2
7/root/A/A-3A-3
优缺点
  • 子树查询效率高

由于其在每个节点都保存了从根节点到自己的路径,因此查询子树非常方便,只需要一次查询即可。
比如查询节点A的所有子节点,只需要执行如下SQL即可:

select * from nodes where path like '/A/B%'
  • 路径组成

首要问题是我们该使用哪个字段来表示和组合路径,一般来说,我们可以使用id或者name来组合路径。

  • 如果使用id字段,一般也就表的主键,这样可以保证路径的唯一性。但是id不能使用UUID之类的字段,否则 path字段会变得非常长。也不能使用自增字段字段,因此其id值不可预测。所以只能使用人工分配的数字值,这就比较麻烦。

  • 如果使用name字段,一般来说name字段是唯一的,但是name字段可能会变化,这样会导致path字段的变化,因此需要额外的处理。

  • 同级路径名称重名

路径组成字段在同级中不允许存在重名。如果存在重名,那么就会导致path字段的唯一性问题,因此path字段的值必须是唯一。

  • 路径长度限制

path字段的长度可能有限制的,因此我们需要限制树的深度。

  • 无序树

同样地,树节点的之间的无序的,与pid树一样,要维护一棵有序树也是比较麻烦的。

  • 更新树结构

路径枚举模型下,如果需要调整树结构,比如将节点/root/A移动到节点/root/B下。

  • 首先需要将节点/root/A的所有子节点的path字段修改为/root/B/A/开头的路径。对应的SQL语句如下:
update nodes set path = replace(path,'/root/A/','/root/B/A/') where path like '/root/A/%'
  • 然后将节点/root/Apath字段修改为/root/B/A。对应的SQL语句如下:
update nodes set path = '/root/B/A' where path = '/root/A'

左右值

存储结构

每个节点都有两个数字,代表了一个范围,这个范围内的所有节点都是它的子节点。这种方法可以方便地查询子树和父节点,但在插入或删除节点时需要更新大量数据。

CREATE TABLE nodes (id INT PRIMARY KEY,leftValue INT,rightValue INT,name VARCHAR(100)
);

示例数据如下:

idlftrgtname
1114root
229A
31011B
41213C
534A-1
656A-2
778A-3

表示的树如下:

  • root
    • A
      • A-1
      • A-2
      • A-3
    • B
    • C
优缺点

左右值结构是一种非常高效的树存储结构,它可以方便地查询子树和父节点。

基本原理是给每个节点分配两个数字,代表了一个范围,这个范围内的所有节点都是它的子节点。

在这里插入图片描述

  • 高效查询

左右值结构可以方便地查询子树和父节点,比如查询节点A的所有子节点,只需要执行如下SQL即可:

select * from nodes where lft > 2 and rgt < 9

左右值结构除了可以方便查询子树外,还可以方便查询:

  • 查询某个节点的所有后代
  • 查询某个节点的祖先节点
  • 查询整棵树
  • 查询子树节点数量
  • 查询兄弟节点

最大的特点就是可以避免pid树面临的的递归查询,效率非常高。

  • 有序树

左右值结构表示的树天然就是有序树,因此不需要额外的字段来维护节点之间的顺序。

  • 更新树结构

由于树是通过左右值来表示的,节点的移动、更新、删除等操作均会造成相关节点的左右值的变化,因此调整树结构时,需要更新大量数据。
每个更新操作均可能涉到多条SQL的执行,因此效率较低。

比如添加子节点:

LOCK TABLE Tree WRITE;
SELECT @parent_id := node_id, @myLeft := lft FROM Tree WHERE name = "Food";
UPDATE Tree SET rgt = rgt + 2 WHERE rgt > @myLeft;
UPDATE Tree SET lft = lft + 2 WHERE lft > @myLeft;
INSERT INTO Tree( name, lft, rgt) VALUES( "Fruit", @myLeft + 1, @myLeft + 2);
UNLOCK TABLES;

更多可以查看这里

闭包表

存储结构

使用一个单独的表来存储每个节点与其所有祖先节点之间的关系。这种方法可以方便地查询子树和父节点,但需要额外的存储空间。

CREATE TABLE nodes (id INT PRIMARY KEY,name VARCHAR(100)
);CREATE TABLE closure (ancestor INT,descendant INT,depth INT,PRIMARY KEY (ancestor, descendant),FOREIGN KEY (ancestor) REFERENCES nodes(id),FOREIGN KEY (descendant) REFERENCES nodes(id)
);

示例数据如下:

nodes 表:

idname
1root
2A
3B
4C
5A-1
6A-2
7A-3

closure 表:

ancestordescendantdepth
110
121
131
141
152
162
172
220
251
261
271
330
440
550
660
770
优缺点
  • 高效查询

通过Join操作也可以比较方便进行查询操作,比如查询节点A的所有子节点,只需要执行如下SQL即可:

select * from nodes n join closure c on n.id=c.descendant where c.ancestor=2
  • 空间换时间

相对于前几种存储结构,ClosureTable结构是一种空间换时间的算法,这也意味着

  • 需要额外的存储空间。
  • 需要额外的Join操作。

总结

  • 邻接列表模型最简单直观,但是无法避免的递归查询让其只能用在一些简单的场合。
  • 路径枚举模型查询效率高,但路径字段选择比较重要,当路径字段更新或重名时,面临很大的问题,所以并不推荐。
  • 左右值模型查询效率高,但是严格的左右值的完整性,使得调整树结构时,需要更新大量数据,效率较低,所以树的结构完整性比较脆弱,任意更新操作均需要进行锁表操作,否则任何错误的左右值更新均可能导致树结构损坏。
  • 闭包表模型查询效率高,但需要额外的存储空间。

总体而言,在以查询为主的场景中,本人更推荐使用左右值的存储结构,因为查询的确是比较方便,并且天然是有序的。

最后给大家推荐一个基于Nodejs下使用基于左右值算法的树存储管理库FlexTree

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

自动驾驶-机器人-slam-定位面经和面试知识系列05之常考公式推导(02)

这个博客系列会分为C STL-面经、常考公式推导和SLAM面经面试题等三个系列进行更新&#xff0c;基本涵盖了自己秋招历程被问过的面试内容&#xff08;除了实习和学校项目相关的具体细节&#xff09;。在知乎和牛客&#xff08;牛客上某些文章上会附上内推码&#xff09;也会同步…

Android APP 音视频(03)CameraX预览与MediaCodec编码

说明&#xff1a; 此CameraX预览和编码实操主要针对Android12.0系统。通过CameraX预览获取yuv格式数据&#xff0c;将yuv格式数据通过mediacodec编码输出H264码流&#xff08;使用ffmpeg播放&#xff09;&#xff0c;存储到sd卡上。 1 CameraX 和 MediaCodec简介 1.1 CameraX…

【CN】Argo 持续集成和交付(一)

1.简介 Argo 英 [ˈɑ:ɡəu] 美 [ˈɑrˌɡo] Kubernetes 原生工具&#xff0c;用于运行工作流程、管理集群以及正确执行 GitOps。 Argo 于 2020 年 3 月 26 日被 CNCF 接受为孵化成熟度级别&#xff0c;然后于 2022 年 12 月 6 日转移到毕业成熟度级别。 argoproj.github.i…

基于Xejen框架实现的C# winform鼠标点击器、电脑按键自动点击器的软件开发及介绍

功能演示 文章开始之前&#xff0c;仍然是先来个视频&#xff0c;以便用户知道鼠标连点器的基本功能 软件主界面 多功能鼠标连点器 快速点击&#xff1a; 痕即鼠标点击器可以设定每秒点击次数&#xff0c;让您轻松应对高频点击需求。 切换时长&#xff0c;即每次动作之间的间…

0719_驱动3 printk使用方法

一、printk使用方法 1.应用层打印使用printf&#xff0c;内核层使用printk 2.如何查看内核层中printk如何使用 3.在内核空间执行grep "printk" * -nR 4.在内核空间执行vi -t KERN_INFO 5.printk有8中打印级别&#xff08;0-7&#xff09;&#xff0c;打印级别用来过滤…

数据结构(Java):反射枚举Lambda表达式

目录 1、反射 1.1 反射的定义 1.2 反射机制的原理 1.3 反射相关类 1.4 Class类 1.4.1 相关方法 1.4.1.1 常用获得类相关的方法 ​编辑 1.4.1.2 常用获得类中属性相关的方法 1.4.1.3 获得类中构造器相关的方法 1.4.1.4 获得类中方法相关的方法 1.4.2 获取Class对象 1.…

linux进程——虚拟地址空间——重新认识进程!!!

前言&#xff1a; 本节内容就将进入linux进程里面的又一个大板块&#xff0c; 博主认为这个板块和PCB的板块是平级——两者独立&#xff1b;之前友友们可能认为进程分为PCB和代码与数据。 但是本节过后&#xff0c; 我们可以对进程重新定义——进程 &#xff08;PCB&#xff0…

深入理解计算机系统 CSAPP 家庭作业11.8

回收子进程是书本537页的内容 在tiny.c文件加以下代码,记得重新编译哦 书中提到CGI是在动态内容中的,所以题目的意思应该是在动态内容里面回收 void handler1(int sig) {int olderrno errno;while (waitpid(-1,NULL,0)>0){Sio_puts("Handler reaped child\n");…

【秋招突围】2024届秋招笔试-OPPO笔试题-第一套-三语言题解(Java/Cpp/Python)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新 OPPO 春秋招笔试题**汇总&#xff5e; &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; ✨ 笔试合集传送们 -> &#x1f9f7;春秋招笔试合集 &#x1f380; 01.K小姐的快…

DVWA中命令执行漏洞细说

在攻击中&#xff0c;命令注入是比较常见的方式&#xff0c;今天我们细说在软件开发中如何避免命令执行漏洞 我们通过DVWA中不同的安全等级来细说命令执行漏洞 1、先调整DVWA的安全等级为Lower,调整等级在DVWA Security页面调整 2、在Command Injection页面输入127.0.0.1&…

【计算机网络】物理层(第2章)大纲(共70+页)

最后只复习了1.5天&#xff0c;应用层简单过了一遍。 本来是mindmap的&#xff0c;但是太大了只能导出成提纲了&#xff0c;凑合看吧orz。 如果你找我要源文件&#xff0c;最好是在2024年&#xff0c;不然我可能就找不到了&#xff08;&#xff09;。

C# Task.WaitAll 的用法

目录 简介 1.WaitAll(Task[], Int32, CancellationToken) 2.WaitAll(Task[]) 3.WaitAll(Task[], Int32) 4.WaitAll(Task[], CancellationToken) 5.WaitAll(Task[], TimeSpan) 结束 简介 Task.WaitAll 是 C# 中用于并行编程的一个的方法&#xff0c;它属于 System.Threa…

蓝牙耳机百元之内怎么选?四款百元精品爆款蓝牙耳机盘点

在蓝牙耳机的海洋中&#xff0c;百元价位仿佛是一片神秘的绿洲&#xff0c;既诱人又充满未知&#xff0c;如何在众多选项中挑选出真正的精品呢&#xff1f;蓝牙耳机百元之内怎么选&#xff1f;这是许多消费者的共同疑问&#xff0c;带着这个疑问&#xff0c;作为蓝牙耳机发烧党…

2024101读书笔记|《飞花令·冬》——三冬雪压千年树,四月花繁百尺藤

2024101读书笔记|《飞花令冬》——三冬雪压千年树&#xff0c;四月花繁百尺藤 《飞花令冬&#xff08;中国文化古典诗词品鉴&#xff09;》素心落雪 编著&#xff0c;飞花令得名于唐代诗人韩翃《寒食》中的名句“春城无处不飞花”&#xff0c;类似于行酒令&#xff0c;是文人们…

在Mac上恢复永久删除的Excel文件,有效方法学习!

丢失 Mac 上的重要 Excel 文件可能是一场噩梦&#xff0c;尤其是如果它们被永久删除的话。相信我&#xff0c;这种感觉是没人愿意经历的。但不要惊慌&#xff1b;您可以选择恢复这些文件。无论是通过垃圾箱删除还是由于系统错误意外丢失&#xff0c;都有多种方法可以恢复您的数…

STM32嵌入式人工智能边缘计算应用教程

目录 引言环境准备边缘计算系统基础代码实现&#xff1a;实现嵌入式人工智能边缘计算系统 4.1 数据采集模块 4.2 数据处理与推理模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;边缘计算与优化问题解决方案与优化收尾与总结 1. 引言 嵌入式人工智…

深度学习的前沿主题:GANs、自监督学习和Transformer模型

&#x1f48e; 欢迎大家互三&#xff1a;2的n次方_ &#x1f48e;1. 介绍 深度学习在人工智能领域中占据了重要地位&#xff0c;特别是生成对抗网络&#xff08;GANs&#xff09;、自监督学习和Transformer模型的出现&#xff0c;推动了图像生成、自然语言处理等多个领域的创…

Docker Desktop安装(通俗易懂)

1、官网 https://www.docker.com/products/docker-desktop/ 2、阿里云镜像 docker-toolbox-windows-docker-for-windows安装包下载_开源镜像站-阿里云 1. 双击安装文件勾选选项 意思就是&#xff1a; Use WSL 2 instead of Hyper-V (recommended) : 启用虚拟化&#xff0c;…

2024年【非高危行业生产经营单位主要负责人解析

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 非高危行业生产经营单位主要负责人及安全管理人员安全生产知识和管理能力考试报名是安全生产模拟考试一点通生成的&#xff0c;非高危行业生产经营单位主要负责人及安全管理人员安全生产知识和管理能力证模拟考试题库…

基于DMASM镜像的DMDSC共享存储集群部署

DMv8镜像模式共享存储集群部署 环境说明 操作系统&#xff1a;centos7.6 服务器&#xff1a;2台虚拟机 达梦数据库版本&#xff1a;达梦V8 安装前准备工作 参考文档《DM8共享存储集群》-第11、12章节 参考文档《DM8_Linux服务脚本使用手册》 1、系统环境(all nodes) 1…