MySQL存储树形数据优化技笔记

摘要:
许多开发人员提出的第一个解决方案通常是记录每个节点的父节点,因此他们需要编写复杂的代码来递归地检索许多记录、路径枚举和闭包表。2.路径枚举(添加一个字段以存储所有父节点信息,因为路径字段包含节点的所有祖先信息,然后使用字符串切割函数处理所有祖先节点。将新节点的ID值(comment_ID)添加到路径的末尾。枚举路径使查询子树和祖先更容易。





640?wx_fmt=png

1、树形结构应用场景

有时我们需要保存一些树形的数据,比如组织架构、话题讨论、知识管理、商品分类等,这些数据之间存在一种递归关系,很多开发人员想到的第一个解决方案往往是记录每个节点的父节点,例如以下的评论表。


CREATE TABLE comments (

    comment_id int(10)  NOT NULL,

    parent_id int(10)  DEFAULT NULL,

    comment text  NOT NULL,

    PRIMARY KEY (comment_id)

) ENGINE=InnoDB DEFAULT CHARSET=utf8


采用这样的结构,就需要编写复杂的代码递归检索很多记录,查询的效率就会很低。如果数据量不大、讨论内容相对固定,数据的层次较少,那么采用这样的结构就会是简单的、清晰的,这种情况下此结构还是合适的;但如果数据量很大,查询就会变得很复杂。下面介绍两种更通用,扩展性更好的解决方案:路径枚举和闭包表。

2、路径枚举(增加一个字段存储所有父级节点信息,用特殊符号分割开)

基于上面的表结构,可以增加一个字段path,用于记录节点的所有祖先信息。记录的方式是把所有的祖先信息组织成一个字符串。

因为路径(path)字段包含了该节点的所有祖先信息,所以可以轻易地获取某个节点的所有祖先节点,可以用程序先获取path字符串,然后再使用切割字符串的函数处理得到所有的祖先节点。

如果要查找某个节点的所有后代,例如查找comment_id等于3的所有后代,可以使用如下的查询语句。

SELECT * FROM comments WHERE path LIKE ‘1/3/_%’;

如果要查找下一层子节点,可以使用如下的查询语句

SELECT * FROM comments WHERE path REGEXP “^1/3/[0-9]+/$”;

插入操作也比较简单,只需要复制一份父节点的路径,并将新节点的ID值(comment_id)添加到路径末尾就可以了。

枚举路径的方式使得查询子树和祖先都变得更加简单,查看分隔符即可知道节点的层次,虽然冗余存储了一些数据,应用程序需要额外增加代码以确保路径信息的正确性,但这种设计的扩展性更好,更能适应未来数据的不断增长。表5-2中,仍然保留了parent_id列,是为了使一些操作更加方便,也可以用来校验路径信息是否正确。

3、闭包表(增加一张父子节点关联关系表)

闭包表也是一种通用的方案,它需要额外增加一张表,用于记录节点之间的关系。它不仅记录了节点之间的父子关系,也记录了树中所有节点之间的关系。

使用如下命令语句新建表path

CREATE TABLE path (

    ancestor int(11) NOT NULL,

    descendant int(11) NOT NULL,

    PRIMARY KEY (ancestor,descendant)

) ENGINE=InnoDB DEFAULT CHARSET=utf8

ancestor表示祖先,descendant表示后代,存储的是comment_id值。

如果要统计comment_id等于3的所有后代(不包括其自身),可以直接搜索path表祖先是3的记录即可得到,查询语句如下:

SELECT COUNT(*) FROM path WHERE ancestor=3 AND descendant <> 3;

为了更方便地查询直接父节点/子节点,可以增加一个path_length字段以表示深度,节点的自我引用path_length等于0,到它的直接子节点的path_length等于1,再下一层为2,以此类推。

如上所述的数据结构,新增了一个表,用于存储节点之间的信息,是一种典型的“以空间换时间”的方案,而且一个节点可以属于多棵树。相对于路径枚举,闭包表的节点关系更容易维护。


文章基于MySQL DBA修炼之道整理,版权属于原作者

免责声明:文章转载自《MySQL存储树形数据优化技笔记》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇asp.net core 身份认证/权限管理系统简介及简单案例CTR预估模型下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Win10安装TensorFlow1.9-GPU版本

前言 前段时间更新自己电脑上的tf1.4到1.9,没想到踩了这么多坑。。。特意记录下来希望可以帮到大家 删除旧版本 如果你电脑上没有安装旧版本的tf,就可以忽略这一步。我是因为想要升级到最新版本,所以需要先卸载旧版本。旧版本是用anaconda安装的,卸载很简单,首先进入安装tf的环境,我的环境是“tensorflow”: activate tensorf...

ArcGIS Engine栅格数据使用总结

jojojojo2002 原文 ArcGIS Engine栅格数据使用总结 简介:ArcGIS Engine栅格数据使用总结,一个栅格数据集由一个或者多个波段(RasterBand)的数据组成,一个波段就是一个数据矩阵。对于格网数据(DEM数据)和单波段的影像数据,表现为仅仅只有一个波段数据的栅格数据集,而对于多光谱影像数据则表现为具有多个波段的栅格数据...

Gojs学习史(一):基本定义

1. gojs定义 初始化时,先简化gojs本身的方法: var Go = go.GraphObject.make; //简化方法 1.1 画布定义 在声明了Go方法之后,接下来就是定义画布: myDiagram = Go(go.Diagram,"myDiagramDiv",{ initialContentAlignment:go.Spot.Cen...

MySQL主从同步原理

mysql主从同步定义 主从同步使得数据可以从一个数据库服务器复制到其他服务器上,在复制数据时,一个服务器充当主服务器(master),其余的服务器充当从服务器(slave)。因为复制是异步进行的,所以从服务器不需要一直连接着主服务器,从服务器甚至可以通过拨号断断续续地连接主服务器。通过配置文件,可以指定复制所有的数据库,某个数据库,甚至是某个数据库上的某...

Hadoop中TeraSort算法分析

1、概述 1TB排序通常用于衡量分布式数据处理框架的数据处理能力。Terasort是Hadoop中的的一个排序作业,在2008年,Hadoop在1TB排序基准评估中赢得第一名,耗时209秒。那么Terasort在Hadoop中是怎样实现的呢?本文主要从算法设计角度分析Terasort作业。 2、算法思想 实际上,当我们要把传统的串行排序算法设计成并行的排序...

scapy安装及SCTP包分析

关于Scapy scapy是一个强大的交互式数据包处理程序(使用python编写)。它能够伪造或者解码大量的网络协议数据包,能够发送、捕捉、匹配请求和回复包等。它可以很容易地处理一些典型操作,比如端口扫描、tracerouting,探测,单元测试,攻击或网络发现(可替代hping,NMAP,arpspoof,ARP-SK,arping,tcpdump,te...