MySQL实现任意级子目录的主要方案以及区别

常见的实现方案及区别

1. 邻接表(Adjacency List)

方案描述:
  • 每条记录存储一个节点的父节点ID。

  • 表结构大致:

    id INT PRIMARY KEY,
    name VARCHAR(...),
    parent_id INT  -- 指向父节点的ID,根节点为NULL或0
    
优点:
  • 结构简单,直观,容易维护。

  • 插入、删除单条节点简单。

缺点:
  • 查询整个树或任意节点的所有子孙节点比较复杂,需递归多次查询(MySQL 8.0之前不支持递归CTE,查询性能低)。

  • 需要递归处理。


2. 路径枚举(Path Enumeration)

方案描述:
  • 每条记录保存从根节点到当前节点的完整路径。

  • 例如路径字段path存储为/1/5/9/

  • 表结构大致:

    id INT PRIMARY KEY,
    name VARCHAR(...),
    path VARCHAR(...)  -- 存储路径字符串
    
优点:
  • 查询所有子孙节点通过LIKE 'path%'即可,查询简单。

  • 不用递归,查询效率较高。

缺点:
  • 修改节点路径(如移动节点)时,需要更新所有子节点路径,操作复杂且成本高。

  • 路径字段存储占用空间较大。


3. 嵌套集合模型(Nested Set Model)

方案描述:
  • 利用左右值(left, right)表示节点的范围区间。

  • 每个节点有两个整数值lftrgt,表示在树中的先序遍历位置。

  • 表结构大致:

    id INT PRIMARY KEY,
    name VARCHAR(...),
    lft INT,
    rgt INT
    
优点:
  • 查询子孙节点非常快(单次范围查询)。

  • 适合大量读,查询频繁的场景。

缺点:
  • 插入、删除、移动节点时,需要调整大量节点的lftrgt值,操作复杂。

  • 维护成本高。


4. 闭包表(Closure Table)

方案描述:
  • 额外建一个关联表,存储节点之间的所有祖先-后代关系。

  • 关联表结构:

    ancestor_id INT,
    descendant_id INT,
    depth INT  -- 距离,0表示自身
    
优点:
  • 查询任意节点的所有子孙和所有祖先非常方便且性能好。

  • 插入删除只需要维护关联表,灵活。

缺点:
  • 需要额外的存储空间。

  • 维护关联表的操作相对复杂。


5. MySQL 8.0+ 的递归公共表表达式(CTE)

  • MySQL 8.0支持递归CTE,邻接表查询树形数据变得更简单。

  • 利用递归CTE实现递归查询,无需额外结构。


总结对比

方案 查询复杂度 插入/更新复杂度 存储成本 适用场景
邻接表 递归查询,慢 简单 数据结构简单,更新频繁
路径枚举 简单LIKE查询 复杂,需更新路径 中等 读多写少,结构变化不频繁
嵌套集合 简单范围查询 复杂,调整左右值 读多写少,查询性能要求高
闭包表 简单且灵活 维护关联表复杂 需要频繁查询任意层级关系
递归CTE(MySQL8+) 简单递归查询 简单 适合任意层级递归查询,无需额外表

你可能感兴趣的:(MySQL实现任意级子目录的主要方案以及区别)