各位用户为了找寻关于浅谈MYSQL中树形结构表3种设计优劣分析与分享的资料费劲了很多周折。这里教程网为您整理了关于浅谈MYSQL中树形结构表3种设计优劣分析与分享的相关资料,仅供查阅,以下为您介绍关于浅谈MYSQL中树形结构表3种设计优劣分析与分享的详细内容
简介
在开发中经常遇到树形结构的场景,本文将以部门表为例对比几种设计的优缺点;
问题
需求背景:根据部门检索人员, 问题:选择一个顶级部门情况下,跨级展示当前部门以及子部门下的所有人员,表怎么设计更合理 ?
递归吗 ?递归可以解决,但是势必消耗性能
设计1:邻接表
注:(常见父id设计)
表设计
? 1 2 3 4 5 6 7 8 9create
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;
这样是最常见的设计,能正确的表达菜单的树状结构且没有冗余数据,但在跨层级查询需要递归处理。
sql示例
1.查询某一个节点的直接子集
? 1select
*
from
dept_info01
where
dept_parent_id =1001
优点
结构简单 ;
缺点
1.不使用递归情况下无法查询某节点所有父级,所有子集
设计2:路径枚举
在设计1基础上新增一个父部门id集字段,用来存储所有父集,多个以固定分隔符分隔,比如逗号。
表设计
? 1 2 3 4 5 6 7 8 9 10create
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;
sql示例
1.查询所有子集 1).通过模糊查询
? 1 2 3 4 5 6select
*
from
dept_info02
where
dept_parent_ids
like
'%1001%'
2).推荐使用 find_in_set 函数
? 1 2 3 4 5 6select
*
from
dept_info02
where
find_in_set(
'1001'
, dept_parent_ids )
优点
方便查询所有的子集 ; 可以因此通过比较字符串dept_parent_ids长度获取当前节点层级 ;缺点
新增节点时需要将dept_parent_ids字段值处理好 ; dept_parent_ids字段的长度很难确定,无论长度设为多大,都存在不能够无限扩展的情况 ;节 点移动复杂,需要同时变更所有子集中的dept_parent_ids字段值 ;
设计3:闭包表
闭包表是解决分级存储的一个简单而优雅的解决方案,这是一种通过空间换取时间的方式 ; 需要额外创建了一张treepaths表它记录了树中所有节点间的关系 ; 包含两列,祖先列与后代列,即使这两个节点之间不是直接的父子关系;同时增加一行指向节点自己 ;表设计
主表
? 1 2 3 4 5 6 7 8create
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;
祖先后代关系表
? 1 2 3 4 5 6 7create
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,一次类推,第几层就是几 。
sql示例
插入新节点
? 1 2 3 4 5insert
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
查询所有祖先
? 1 2 3 4 5 6 7select
c.*
from
dept_info03
as
c
inner
join
dept_tree_path_info t
on
c.dept_id = t.ancestor
where
t.descendant = 3001
查询所有后代
? 1 2 3 4 5 6 7select
c.*
from
dept_info03
as
c
inner
join
dept_tree_path_info t
on
c.dept_id = t.descendant
where
t.ancestor = 1001
删除所有子树
? 1 2 3 4 5 6 7 8 9 10 11delete
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
)
删除叶子节点
? 1 2 3 4 5delete
from
dept_tree_path_info
where
descendant = 2001
移动节点
删除所有子树(先断开与原祖先的关系) 建立新的关系优点
非递归查询减少冗余的计算时间 ; 方便非递归查询任意节点所有的父集 ; 方便查询任意节点所有的子集 ; 可以实现无限层级 ; 支持移动节点 ;缺点
层级太多情况下移动树节点会带来关系表多条操作 ; 需要单独一张表存储对应关系,在新增与编辑节点时操作相对复杂 ;
结合使用
可以将邻接表方式与闭包表方式相结合使用。实际上就是将父id冗余到主表中,在一些只需要查询直接关系的业务中就可以直接查询主表,而不需要关联2张表了。在需要跨级查询时祖先后代关系表就显得尤为重要。
表设计
主表
? 1 2 3 4 5 6 7 8 9create
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;
祖先后代关系表
? 1 2 3 4 5 6 7create
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;
总结
其实,在以往的工作中,曾见过不同类型的设计,邻接表,路径枚举,邻接表路径枚举一起来的都见过。每种设计都各有优劣,如果选择设计依赖于应用程序中哪种操作最需要性能上的优化。
综上所述
只需要建立子父集关系中可以使用邻接表方式 ; 涉及向上查找,向下查找的需要建议使用闭包表方式 ;到此这篇关于浅谈mysql中树形结构表3种设计优劣分析与分享的文章就介绍到这了,更多相关mysql 树形结构表内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
原文链接:https://blog.csdn.net/qq_38011415/article/details/95462698