在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
简介在开发中经常遇到树形结构的场景,本文将以部门表为例对比几种设计的优缺点; 问题需求背景:根据部门检索人员, 递归吗 ?递归可以解决,但是势必消耗性能 设计1:邻接表注:(常见父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; 这样是最常见的设计,能正确的表达菜单的树状结构且没有冗余数据,但在跨层级查询需要递归处理。 SQL示例1.查询某一个节点的直接子集 SELECT * FROM dept_info01 WHERE dept_parent_id =1001 优点 结构简单 ; 缺点 1.不使用递归情况下无法查询某节点所有父级,所有子集 设计2:路径枚举在设计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; SQL示例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 ) 优点
缺点
设计3:闭包表
表设计主表 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,一次类推,第几层就是几 。 SQL示例插入新节点 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; 总结其实,在以往的工作中,曾见过不同类型的设计,邻接表,路径枚举,邻接表路径枚举一起来的都见过。每种设计都各有优劣,如果选择设计依赖于应用程序中哪种操作最需要性能上的优化。
综上所述
到此这篇关于浅谈MYSQL中树形结构表3种设计优劣分析与分享的文章就介绍到这了,更多相关MYSQL 树形结构表内容请搜索极客世界以前的文章或继续浏览下面的相关文章希望大家以后多多支持极客世界! |
请发表评论