MySQL递归查询——数据平坦化新思维

最近在做Oracle到MySQL的数据库的移植过程。两者之间的诸多差别(比如MySQL不支持ADO、函数不一致、唯一索引限制不一样等等)都易于解决,但有一个问题却困扰我们良久:Oracle的递归查询(select... from ... start with ... connect by ... where...子句)在MySQL中不受支持。

在SQL Server2000(2005已经支持递归查询)和DB2中,都可以使用存储过程的方式,在存储过程中完成对数据库的递归检索,并返回记录集的方式实现;但是MySQL数据库可以用存储过程完成递归,但存储过程本身不能返回临时的记录集。

首先,最先想到的是采用临时表的方案解决(网上很多大哥都用的这种方案),但做了一个效率测试,在10w条数据中使用临时表递归检索,1分钟过去了,5分钟过去了,10分钟过去了,半小时过去了……没有返回(后边测试了500条数据需要接近8秒钟时间)。临时表方案效率肯定是有问题的。

然后,公司的DB大佬支招了:使用一个字符串字段(称为“编码”,字段名称比如命名为innerID)来表示记录的父子关系。核心思想是为需要递归的表添加三个字段(摘录自同事的设计文档):

  • 节点编码:为当前记录行的编码(内部编码),它的所有直接下级记录行的编码都是以他为依据进行扩展,他的所有直接下级记录行的上级编码为这个值。
  • 上级编码:为上级记录行对应的编码,这是查询某个节点的下属节点或者下下属节点的依据。
  • 最后编码:为目前分配到最后一个下级记录行的编码,为增加下一个下级记录行提供快速计算的依据。

各个记录行的“编码”如下图所示。

MySQL递归查询鈥斺斒萜教够滤嘉

这种方案的确可以很好的解决查询某行下所有子行的符合条件的记录集的问题。只需要形如SELECT * FROM xxx WHEREinnerID LIKE "A0ZZ%" [AND othercondition]的查询条件即可检索出A0ZZ记录及其所有下属节点的符合条件的记录集。

但是,导致了另外一个问题的产生:当对某个父记录集节点(特别是位于根节点下的二级节点)进行移动位置时,将会是致命的(需要修改所有的innerID,并且如果要考虑文件夹的合并的话,那将更加复杂),如果还要考虑多终端的并发性问题,会出现的问题将非常复杂。

所以,这个方案可以作为备选方案(需要在我们的产品SPEC中加入一些Limitation),但最好能找到更好的解决方案。

最好,在我们同事的不懈努力下,在MySQL的论坛中找到了一种更加合理的方案。

其实,这个方案我们也应该早就可以想到,特别是在倡导“扁平化管理”的今天。它的核心思想就是将递归所实现的层级化结构,使用数字按照嵌套的思路实现扁平化,截图(来自原网页):

MySQL递归查询鈥斺斒萜教够滤嘉

(层级化结构)

MySQL递归查询鈥斺斒萜教够滤嘉

(转化为嵌套后的平坦化结构) 

具体方案可以参考原始网页:http://dev.mysql.com/tech-resources/articles/hierarchical-data.html

使用这种方案,相比于前一个方案,一方面在查询的时候可以省掉字符串的LIKE关键字,有助于提升效率;另外一方面,在对数据集进行修改时,也只需要对增加的左值和右值节点,进行批量的UPDATE(增加一定的数字或者减少一定的数字,但效率需要测试),不需要更复杂的逻辑,在并发性上也可以处理得更好。

总结:其实扁平化不光是在管理上,也可以在技术中,MySQL的递归查询只是一个简单的例子,我们在开发过程中,如果能够换个角度想问题,也许可以有更多更好的解决方案。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值