原理
核心思想
- • 通过空间换时间策略,预先存储所有节点间的层级关系。
- • 包含两个表:
- 1. 主表:存储节点基本信息(如部门、分类)。
- 2. 闭包表:记录所有祖先-后代关系及路径长度。
表结构示例
-- 主表(存储节点)
CREATE TABLE department (
id INT PRIMARY KEY,
name VARCHAR(50)
);
-- 闭包表(存储关系)
CREATE TABLE department_closure (
ancestor_id INT, -- 祖先节点
descendant_id INT, -- 后代节点
depth INT, -- 路径长度(直接子节点=1)
PRIMARY KEY (ancestor_id, descendant_id)
);
数据示例
树结构:A → B → C
闭包表记录:
ancestor_id | descendant_id | depth |
A | A | 0 |
A | B | 1 |
A | C | 2 |
B | B | 0 |
B | C | 1 |
C | C | 0 |
操作示例
查询所有后代(如查询A的子节点)
SELECT d.*
FROM department d
JOIN department_closure c ON d.id = c.descendant_id
WHERE c.ancestor_id = 'A' AND c.depth >= 1;
插入新节点(如插入C作为B的子节点)
-- 插入主表
INSERT INTO department (id, name) VALUES ('C', 'Sub');
-- 更新闭包表
INSERT INTO department_closure (ancestor_id, descendant_id, depth)
SELECT ancestor_id, 'C', depth + 1 FROM department_closure
WHERE descendant_id = 'B' -- B的所有祖先
UNION ALL SELECT 'C', 'C', 0; -- 自身关系
删除节点(如删除B及其子树)
DELETE FROM department_closure
WHERE descendant_id IN (
SELECT descendant_id FROM department_closure
WHERE ancestor_id = 'B'
);
优缺点对比
优点 | 缺点 |
✅ 无需递归,查询效率高 | ❌ 存储空间大(记录所有路径) |
✅ 支持任意深度查询 | ❌ 增删需维护闭包表 |
✅ 结构清晰易理解 | ❌ 频繁更新时维护成本高 |
适用场景
- 1. 读多写少:组织架构、商品分类、评论回复等。
- 2. 复杂查询需求:快速获取后代/祖先/路径长度。
对比其他存储方案
方案 | 查询效率 | 增删效率 | 存储空间 | 复杂度 |
邻接表 | 低 | 高 | 小 | 简单 |
嵌套集 | 高 | 低 | 中 | 复杂 |
路径枚举 | 中 | 中 | 中 | 中 |
闭包表 | 高 | 中 | 大 | 中 |