目录简介问题设计1:邻接表表设计sql示例设计2:路径枚举表设计SQL示例设计3:闭包表表设计SQL示例结合使用表设计总结简介 在开发中经常遇到树形结构的场景,本文将以部门表为例对比
在开发中经常遇到树形结构的场景,本文将以部门表为例对比几种设计的优缺点;
需求背景:根据部门检索人员,
问题:选择一个顶级部门情况下,跨级展示当前部门以及子部门下的所有人员,表怎么设计更合理 ?
递归吗 ?递归可以解决,但是势必消耗性能
注:(常见父Id设计)
CREATE TABLE `dept_info01` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`dept_id` int(10) NOT NULL COMMENT '部门id',
`dept_name` varchar(100) NOT NULL COMMENT '部门名称',
`dept_parent_id` int(11) NOT NULL COMMENT '父部门id',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
这样是最常见的设计,能正确的表达菜单的树状结构且没有冗余数据,但在跨层级查询需要递归处理。
1.查询某一个节点的直接子集
SELECT * FROM dept_info01 WHERE dept_parent_id =1001
优点
结构简单 ;
缺点
1.不使用递归情况下无法查询某节点所有父级,所有子集
在设计1基础上新增一个父部门id集字段,用来存储所有父集,多个以固定分隔符分隔,比如逗号。
CREATE TABLE `dept_info02` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`dept_id` int(10) NOT NULL COMMENT '部门id',
`dept_name` varchar(100) NOT NULL COMMENT '部门名称',
`dept_parent_id` int(11) NOT NULL COMMENT '父部门id',
`dept_parent_ids` varchar(255) NOT NULL DEFAULT '' COMMENT '父部门id集',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
1.查询所有子集
1).通过模糊查询
SELECT
*
FROM
dept_info02
WHERE
dept_parent_ids like '%1001%'
2).推荐使用 FIND_IN_SET 函数
SELECT
*
FROM
dept_info02
WHERE
FIND_IN_SET( '1001', dept_parent_ids )
优点
缺点
主表
CREATE TABLE `dept_info03` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`dept_id` int(10) NOT NULL COMMENT '部门id',
`dept_name` varchar(100) NOT NULL COMMENT '部门名称',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
祖先后代关系表
CREATE TABLE `dept_tree_path_info` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`ancestor` int(10) NOT NULL COMMENT '祖先id',
`descendant` int(10) NOT NULL COMMENT '后代id',
`depth` tinyint(4) NOT NULL DEFAULT '0' COMMENT '层级深度',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
注:depth 层级深度字段 ,自我引用为 1,直接子节点为 2,再一下层为 3,一次类推,第几层就是几 。
插入新节点
INSERT INTO dept_tree_path_info (ancestor, descendant,depth)
SELECT t.ancestor, 3001,t.depth+1 FROM dept_tree_path_info AS t
WHERE t.descendant = 2001
UNION ALL
SELECT 3001,3001,1
查询所有祖先
SELECT
c.*
FROM
dept_info03 AS c
INNER JOIN dept_tree_path_info t ON c.dept_id = t.ancestor
WHERE
t.descendant = 3001
查询所有后代
SELECT
c.*
FROM
dept_info03 AS c
INNER JOIN dept_tree_path_info t ON c.dept_id = t.descendant
WHERE
t.ancestor = 1001
删除所有子树
DELETE
FROM
dept_tree_path_info
WHERE
descendant IN
(
SELECT
a.dept_id
FROM
( SELECT descendant dept_id FROM dept_tree_path_info WHERE ancestor = 1001 ) a
)
删除叶子节点
DELETE
FROM
dept_tree_path_info
WHERE
descendant = 2001
移动节点
优点
缺点
可以将邻接表方式与闭包表方式相结合使用。实际上就是将父id冗余到主表中,在一些只需要查询直接关系的业务中就可以直接查询主表,而不需要关联2张表了。在需要跨级查询时祖先后代关系表就显得尤为重要。
主表
CREATE TABLE `dept_info04` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`dept_id` int(10) NOT NULL COMMENT '部门id',
`dept_name` varchar(100) NOT NULL COMMENT '部门名称',
`dept_parent_id` int(11) NOT NULL COMMENT '父部门id',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
祖先后代关系表
CREATE TABLE `dept_tree_path_info` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键',
`ancestor` int(10) NOT NULL COMMENT '祖先id',
`descendant` int(10) NOT NULL COMMENT '后代id',
`depth` tinyint(4) NOT NULL DEFAULT '0' COMMENT '层级深度',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
其实,在以往的工作中,曾见过不同类型的设计,邻接表,路径枚举,邻接表路径枚举一起来的都见过。每种设计都各有优劣,如果选择设计依赖于应用程序中哪种操作最需要性能上的优化。
设计 | 表数量 | 查询直接子 | 查询子树 | 同时查询多个节点子树 | 插入 | 删除 | 移动 |
---|---|---|---|---|---|---|---|
邻接表 | 1 | 简单 | 需要递归 | 需要递归 | 简单 | 简单 | 简单 |
枚举路径 | 1 | 简单 | 简单 | 查多次 | 相对复杂 | 简单 | 复杂 |
闭包表 | 2 | 简单 | 简单 | 简单 | 相对复杂 | 简单 | 复杂 |
综上所述
到此这篇关于浅谈Mysql中树形结构表3种设计优劣分析与分享的文章就介绍到这了,更多相关mysql 树形结构表内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
--结束END--
本文标题: 浅谈MYSQL中树形结构表3种设计优劣分析与分享
本文链接: https://lsjlt.com/news/136325.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-10-23
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
2024-10-22
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0