树形结构设计

树形结构设计

        前一段时间和一位同事讨论了树形结构表设计,今天将讨论的邮件整理了一下,合并成文希望大家一起来讨论。
        树形结构是我们开发中很长用到的结构,很多功能为了展示层次关系往往都使用树形结构来存储,对于树形结构数据库表设计也各有各的方法,在不同的需求下我们设计不同的结构来满足要求。这里我介绍一下我之前开发中设计的树形表。

一、 节点表+关系表
        如果你的业务需求中,需要平凡的更改表结构,例如:插入、变更节点位置或者一个节点可以被包含在多个节点中,“节点表+关系表”的设计就比较适合。

这样的设计包含2张表:
节点表:用来存放所有的接点
包含字段 CHILD_ID     NAME

关系表:用来存放接点表中各接点间的关系
包含字段 LINK_ID      CHILD_ID     PARENT_LINK_ID

        节点表顾名思义就是用来存放各节点具体数据如名字等,关系表是用来存放节点关系的关系(对你没有看错是关系的关系)!很多人可能不是很好的理解这个概念,简单的讲就是关系表里存放的是各个关系间的关系,用这个关系表可以连接出一个节点的所有路径。
举个例子:
现在需要设计一个三层节点
A1,A2,A3是第一层的3个数据
B1,B2是第二层
C1,C2是第三层

节点A1
        节点B1
                 节点C1
节点A2
         节点B1
                  节点C2
节点A3
         节点B2

A1-C1这条路径在关系表中的记录包含
LINK_ID        CHILD_ID       PARENT_LINK_ID
1             A1               NULL
2             B1                1
3             C1                2

        这样当我们希望找到A1以及它的子节点时就可以通过递归查找到所有的节点。看了第一个例子可能有人会问为什么不直接使用PARNET_CHILD_ID而要饶一圈使用PARENT_LINK_ID(关系的关系)呢?其实这样设计是为了考虑到另一种情况,也就是A2节点的情况,大家发现没有B1节点即在A1下又在A2下,这样的情况很常见比如外置网卡它即可以被归类为配件分类下,也可以被放在网络产品分类下,这样如果单独查找节点就会出现二义性路径。使用关系连接就解决了这个问题。
        这样的节点同时还带来的结构的可维护性,就像我开头时候说的,如果你希望向某个节点下插入一个新的节点(或是移动),你只需要往关系表中建立一条新的关系数据即可。
        同样带来优点的同时它也有很明显的缺点,我们知道关系数据库的查询语句(如T-SQL)是很难编写递归关系的(特别是在不知道结构层次的情况下),以上面的结构为例子,如果我们希望查找所有A1节点下的子节点,就必须取出所有的数据然后在程序中通过递归排列关系才能输出,无法使用一句SQL语句就将关系安顺序建立起来。这也是为什么我一开始说如果大家业务需求中对树结构变动非常平凡的话这样的设计就很适合。如果树结构相对稳定,变动的仅仅只是节点的值或者只有删除和新增(非插入)操作这样的结构可能就不是很适合。
        顺便说一下这样的结构还可以用来作为快速查找时的路径索引,当然这个不是本次讨论的范围这里只是提一下。
二、 包含路径结构表
        很多时候树形结构用来存放配置信息等,它的结构是很稳定的,唯一变化的就是每个节点中的值,果需求如此我们就可以将表设计为包含路径信息方便查找。这样的设计只需要一张节点表,并在其中添加1个字段PATH即可。
举个例子:
现在有个配置节点的关系,数字表示节点编号
顶层 -0-
         节点 -0-1-
                   节点 -0-1-1-
                   节点 -0-1-2-
         节点 -0-2-
                   节点 -0-2-1-
                            节点 -0-2-1-1-
                  节点 -0-2-2-
                            节点 -0-2-2-1-
                                     节点 -0-2-2-1-1-
        我们可以看到上面节点是个多层节点,在没有PATH路径字段的情况下,如果我们想要查找2节点下的所有数据(所有子节点下的子节点)我们就必须写一个递归来实现,无法使用一句SQL查询语句来完成关系建立,为了解决这个问题,我们加上了Path字段,也就是看到的“节点”后面以“-”隔开的数字,就是当前节点的路径。当我们希望查找2节点后面的所有节点和子节点时我们只需要写SQL
SLELECT 节点名 FROM TABLE WHERE PATH LIKE ‘-2-%’
如果要查找所有节点
SLELECT 节点名 FROM TABLE WHERE PATH LIKE ‘-0-%’

        就能查出所有查找节点下数据,这样做还有一个好处就是你不需要在通过递归来建立他们的关系,你只需要通过排序使用 ORDER BY PATH 就能按路径将每个节点按照主子关系排列。
        同样他的缺点也很明显,即当非叶子节点上需要新增一个节点将导致雪崩效应,即下面的所有子节点都必须修改PATH,但是如果需求只需要编辑叶节点,而上面的节点相对稳定这个方法就很好。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值