云计算、AI、云原生、大数据等一站式技术学习平台

网站首页 > 教程文章 正文

在数据库设计中如何采用树结构存储以及树结构和列表结构的优劣势

jxf315 2025-07-27 21:23:39 教程文章 1 ℃

最近在开发大量文件存储,标记,检索功能的时候遇到存储结构的选择,一个是树结构,一个是列表结构。平常用列表结构存储数据比较多,不熟悉在数据库中存储树结构的方式,因此做了以下分析。

在使用数据库存储树结构时,有多种设计方法。常见的方式包括 邻接列表法(Adjacency List)路径枚举法(Path Enumeration / Materialized Path)嵌套集法(Nested Set)闭包表法(Closure Table)。这几种方式各有优劣:

树结构存储方式

1.邻接列表法(Adjacency List)

表结构

CREATE TABLE nodes (
  id INTEGER PRIMARY KEY,
  parent_id INTEGER,      -- 指向父节点id,如果为NULL就是根节点
  name TEXT
);

示例数据

id

parent_id

name

1

NULL

Root

2

1

Child1

3

1

Child2

4

2

SubChild

优缺点

  • 优点:简单、易理解,增删改方便。
  • 缺点:查找某节点的所有祖先/后代较繁琐,要多次查询。

2.路径枚举法(Materialized Path)

节点保存一条路径字符串。

表结构

CREATE TABLE nodes (
  id INTEGER PRIMARY KEY,
  path TEXT,      -- 例如 '/1/2/4/' 表示根到本节点的完整路径
  name TEXT
);

查询举例

  • 查询某节点的所有子孙:SELECT * FROM nodes WHERE path LIKE '/1/2/%'
  • 查询某节点的所有祖先,需分割path。

优缺点

  • 优点:后代/祖先查找效率高。
  • 缺点:增删节点时,可能批量更新子节点path。

3.嵌套集法(Nested Set)

用 left/right 数值区间表示层级关系。

表结构

CREATE TABLE nodes (
  id INTEGER PRIMARY KEY,
  lft INTEGER,
  rgt INTEGER,
  name TEXT
);

查询举例

  • 查询所有子孙:SELECT * FROM nodes WHERE lft > ? AND rgt < ?
  • 维护复杂,增删节点需整体调整区间。

优缺点

  • 优点:查询整棵子树非常高效。
  • 缺点:插入/删除性能低,实现复杂。

4.闭包表法(Closure Table)

单独建一张关系表,记录所有祖先-后代关系。

CREATE TABLE nodes (
  id INTEGER PRIMARY KEY,
  name TEXT
);

CREATE TABLE node_closure (
  ancestor_id INTEGER,
  descendant_id INTEGER
);

查询举例

  • 优点:后代/祖先查找简单高效,结构灵活。
  • 缺点:维护多一张表,插入/删除时要做多行修改。

树结构存储推荐实践

最常用的是 邻接列表法,其表设计简单,适合大多数业务场景。若需高效查询整棵子树,推荐使用“路径枚举”或“闭包表”。

树结构和列表结构优劣势

1.列表结构

优点

  • 简单易懂:结构扁平,设计和实现都很简单。
  • 查询高效:大多数情况下一张表就可以完成常规的增、删、查、改操作,SQL语句简单,性能较好。
  • 维护方便:数据维护和管理相对容易,适合大部分无层级需求的业务场景。

缺点

  • 无法表达层级关系:对于需要层次结构的数据(如组织架构、分类树),表达能力有限,只能匮乏地表现。
  • 无法实现递归操作:如查找某个元素的所有子孙元素、祖先元素等会非常困难,需要反复查询。

2.树形结构

常见的实现方式

  • 父子节点(Parent-Child)模式:每条记录有一个parent_id,指向自己的父节点。
  • 路径枚举(Path Enumeration):每条记录记录从根到自身的全路径,如A/B/C
  • 嵌套集(Nested Set):左右值算法preorder、postorder遍历树时编号,方便整棵子树的查询。

优点

  • 表达层级关系:很适合表达有上下级或树状关系的数据,如菜单、组织架构等。
  • 灵活性强:可以轻松支持无限层级的结构。
  • 支持递归查询:尤其在支持WITH RECURSIVECONNECT BY的数据库中,递归查询祖先、子孙非常方便。

缺点

  • 查询复杂:对比列表结构,查询层级关系时SQL相对复杂,性能有所下降,尤其树高度较大时。
  • 维护成本高:某些实现(如嵌套集)对于插入、删除、移动节点操作维护成本较高。
  • 性能问题:深层树结构可能导致递归查询性能较差。

3.总结

  • 如果业务上没有层级关系,只需扁平展示数据,列表结构更为高效、简单。
  • 如果必须表现数据的上下级、层级关系(如菜单、分类树),树形结构更合适,但需要特殊的表设计和更复杂的SQL支持。

因此在此次的功能中,使用列表结构更为合适,理由如下:一是业务本身树形结构展示不需要太频繁,文件之间的上下级关系并不常见,反而通过检索方式查找更常用。二是列表形式更适用于各类打标签和时间、优先级等方式的排序。

最近发表
标签列表