【表结构设计】深入浅出地在关系型数据库中设计表结构-树

568 阅读5分钟

背景

日常需求开发过程中,相信大家一定会遇到树形结构的数据,如企业的组织架构、文件夹等形式的数据,那么如何在关系型数据库中设计其表结构,来储存这种树状数据,从而减少开发党的代码量,提高日常开发效率。

概括

通过步步深入的方式,不断地对表结构进行优化与设计,让大家更加深刻的了解其原理。

1、邻接表模型(递归)

CREATE TABLE `tree_node` (
  `id` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '主键',
  `party_id` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '所属团体id,party表id',
  `parent_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '父节点id',
  `name` varchar(256) COLLATE utf8mb4_bin NOT NULL COMMENT '名称',
  `number` varchar(128) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '冗余账号',
  `type` smallint NOT NULL COMMENT '节点类型 0:非叶子节点;1:叶子节点',
  `create_time` bigint NOT NULL COMMENT '创建时间',
  `modify_time` bigint NOT NULL COMMENT '修改时间',
  `creator_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '创建人',
  `modifier_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '最后修改人',
  `is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '删除标志位'
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='树节点'

只储存树节点的parent_id(父节点ID)

优点: 表结构非常简单,但在实际使用场景中作用不大。

缺点: DDDD,比如某想要某个节点下所有数据,得用递归的方式来查,等等。

2、路径枚举法模型

-- 树节点表结构(路径枚举法)
CREATE TABLE `tree_node` (
  `id` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '主键',
  `parent_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '父节点id',
  `name` varchar(256) COLLATE utf8mb4_bin NOT NULL COMMENT '名称',
  `path` varchar(512) COLLATE utf8mb4_bin NOT NULL COMMENT '路径',
  `type` smallint NOT NULL COMMENT '节点类型 0:非叶子节点;1:叶子节点',
  `short_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'uuid压缩为8位的数据'
  `create_time` bigint NOT NULL COMMENT '创建时间',
  `modify_time` bigint NOT NULL COMMENT '修改时间',
  `creator_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '创建人',
  `modifier_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '最后修改人',
  `is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '删除标志位',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='树节点'

示例数据如下

idparent_idnametypepathshort_id
1--中心0/4030eac24030eac2
21中心底下部门A0/4030eac2/ff24cce8ff24cce8
31中心底下部门B0/4030eac2/e2f8abc2e2f8abc2
42部门A的人C1/4030eac2/ff24cce8/b7d687f1b7d687f1
53部门B的人D1/4030eac2/e2f8abc2/c7bc4b5cc7bc4b5c

多存储树节点在树中的路径,唯一ID,两个数据

优点: 在查找树节点等操作上,更加方便、快捷。

缺点: 当某个节点发生移动时,其底下的子节点的记录的路径均要发生改变,就意味着需要修改大量数据。

快捷操作示例

查询某个节点下的所有节点数据。

select * FROM tree_node tn WHERE  tn.path like '某节点的path%'
优点:使用like '某节点的path%'(左匹配),还可以走索引。一条语句就可以查出数据,还super快。

示例小结: 其他还有可以有很多操作,比如删除某个节点下所有数据等,都可以围绕节点的path来进行操作。

3、实战应用(以企业组织树为例)

场景说明

在实际开发过程中,组织树的数据,肯定是有多种数据的,如部门、人等,如何设计tree_node表结构,来增加效率与性能?

解决思路

  • 如果有很多个对象的话,那在tree_node表中来储存这些对象的属性,肯定是不合适的。那我们可以添加一个字段data_id,来储存对应的数据的ID,如user表的ID,这样比如要查询树下,这个人的数据,只要拿着data_id去user表中查对应的数据即可。
  • tree_node中应该只存放简单的数据,如name等简单的数据,方便进行展示,提高效率。
  • 在tree_node表中添加data_type字段用于区别不同对象,来增加tree_node表的复用性,如果有多种树形结构的数据,使用data_type进行区分。
  • 为方便查找数据,也可以再冗余一个字段parent_data_id(父节点的data_id)。

最终表结构

CREATE TABLE `tree_node` (
  `id` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '主键',
  `parent_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '父节点id',
  `tree_node_index` bigint NOT NULL COMMENT '该分组下的位序',
  `path` varchar(512) COLLATE utf8mb4_bin NOT NULL COMMENT '路径',
  `short_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT 'uuid压缩为8位的数据',
  `type` smallint NOT NULL COMMENT '节点类型 0:非叶子节点;1:叶子节点',
  `data_id` varchar(32) COLLATE utf8mb4_bin NOT NULL COMMENT '节点数据id',
  `data_type` smallint NOT NULL COMMENT '节点数据类型',
  `parent_data_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '父节点数据',
  `name` varchar(256) COLLATE utf8mb4_bin NOT NULL COMMENT '名称',
  `name_pinyin_for_search` varchar(512) COLLATE utf8mb4_bin NOT NULL COMMENT '名称全拼、简拼等,主要用于搜索',
  `create_time` bigint NOT NULL COMMENT '创建时间',
  `modify_time` bigint NOT NULL COMMENT '修改时间',
  `creator_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '创建人',
  `modifier_id` varchar(32) COLLATE utf8mb4_bin DEFAULT NULL COMMENT '最后修改人',
  `is_deleted` tinyint NOT NULL DEFAULT '0' COMMENT '删除标志位',
  PRIMARY KEY (`id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin COMMENT='树节点数据'

备注:欢迎大佬们指点下这种设计方式存在的不足之处。

总结

1、简单来说这种方式的思维也就是用空间换时间。多冗余一些数据,方便查询与展示。