mysql 数据库设计 上下级问题

命名一直是个纠结的问题 发布于 2013/11/29 11:48
阅读 2K+
收藏 0

现在有个应用商家可以添加下级,下级又可以添加下级 相当于无限级.

商家下面有后台的操作员,有面向市场的用户,设备等

需求是 当前操作的商家能够看到他下级 下下级 下下下级....的数据

现在的处理方式是 先查出当前操作商家的所有下级 id (递归出来的)

然后根据id 用where in取数据 ,现在发现性能很低,后来查看sql发现in后面有上千个 id 而且建立的索引页失效了

现在又想了种方法 就是 商家在添加下级的时候 把他上级 上上级...的id组成字符串存储在下级的某个字段里如:当前商家的id为1000,它的上级的所有id格式",0,1,2,3,5,8,9,10,999,"那么他的下级就是",0,1,2,3,5,8,9,10,999,1000" 假如现在有个商家3要查看他所有下级的数据 就用 like '%,3,%' 取数据后来想到like的这种方法索引不能生效,可能效率低,就用全文索引 当时 我现在做了测试数据 用全文索引 match against的效率还不如like 的效率 先在就纠结了....

问啥全文索引的效率会比 like的低呢

还有就是求一种设计方法.


华丽的分割线

-------------------------------------------------------------------------------------------------

问题补充:

现在的业务是这样的关系



看了很多人都说左右值编码,想可不可以在 所有与商家关联的表如:市场用户,用户日志 等表里面加入商家的左右值 查询的时候就按照左右值查询这样效率肯定要搞点 但是 如果商家 级别发生改变 如 有5级在2级添加商家,现在就要修改所有的含有商家左右值得表 这样性能就又下降了...

加载中
0
Tuesday
Tuesday

保存上级的所有id格式",0,1,2,3,5,8,9,10,999,"
只能说, 这会让你的业务代码增加N倍, 你得考虑假如上级变更, 删除, 增加后, 你得同时修改多少家下下家? 比如省长级别增加一个副省长, 那下面的市长, 镇长, 村长都得更改.

个人觉得还是无限分类比较好,  where in之后的结果可以cache起来.
就拿58.com的无限分类来说, 可以肯定不会超过10万条, 也就是6级分类, 讲"无限"这个概念都是扯淡. 要能做到无限数据, 你也不会在这问了

命名一直是个纠结的问题
命名一直是个纠结的问题
嗯 就是还没考虑到改变数据这块,现在也只是个想法 where in之后的结果可以cache起来 关键是当前登录的商家不能判断是哪个 而且查询的方式也多样性 相应的数据表也比较多做cache还真有点不好做,关键是没做过​
0
huan
huan
现在有很成熟的树形结构存储方案了,搜索一下左右值编码树形结构。
命名一直是个纠结的问题
命名一直是个纠结的问题
谢谢 先了解下先,还知道这玩意
0
张亦俊
张亦俊

用逗号分是绝对不行的!!!!

这相当与直接干掉了RDB设计的第一范式,连第一范式都不遵守的RDB设计还不如直接用文件系统。

前面的解决方案是对的,但是需要使用递归查询,MySQL的递归查询比较麻烦,你可以去查一下,性能不保证。

有条件的话,还是换好一点的数据库产品吧。

命名一直是个纠结的问题
命名一直是个纠结的问题
递归不是 递归查询,是表里面的数据全部取出来 程序递归 出来所有子集,只查询一次
0
大喵哥
大喵哥
递归查询难道你要一次性全部查出来? 这棵树,你不能异步加载啊?
命名一直是个纠结的问题
命名一直是个纠结的问题
当初是这样设计的,但是....业务要求,当初是树菜单不好看,后来取消了 就一个列表显示子级全部数据
大喵哥
大喵哥
当点击下一级的时候,再把下一级的东西查询出来
0
mark35
mark35
楼主搜索下 先序遍历 这种数据结构。用左右值来搜索所有子元素来替代递归查询效率极高,缺点是插入的效率低
命名一直是个纠结的问题
命名一直是个纠结的问题
嗯 根据@huan所说了解了下这种方式能解决单纯的树 可现在我们的业务关系是 说不清楚 还是见问题的补充吧
0
张亦俊
张亦俊

引用来自“张亦俊”的答案

用逗号分是绝对不行的!!!!

这相当与直接干掉了RDB设计的第一范式,连第一范式都不遵守的RDB设计还不如直接用文件系统。

前面的解决方案是对的,但是需要使用递归查询,MySQL的递归查询比较麻烦,你可以去查一下,性能不保证。

有条件的话,还是换好一点的数据库产品吧。

先说一下,如果MySQL不支持高效的递归查询,我以下说的都是放屁。

在这里假设有表定义Rec(ID PK, Parent ID, Info1, Info2,...)。ParentID即是上级ID。

假设要求查询所有ID=1的下级信息(Info1, Info2, ...),SQL这么写:

WITH Children AS 
(
SELECT ID,ParentID,Info1 FROM Rec WHERE ParentID=1 --递归的起点
UNION ALL  --把每级递归的结果并起来
SELECT Rec.ID,Rec.ParentID,Rec.Info1
FROM Rec INNER JOIN Children on Children.ID=Rec.ParentID 
--选择ParentID在当前结果集中的纪录
)
SELECT * FROM Children

这种是比较通用的写法,我用的SQL Server,没问题。Oracle还有connect by这种高级货,但解决问题是一样的。

之前没看补充,我就再啰嗦一句,Children是用WITH定义出来的表,可以和其他表做连接之类的操作的。

张亦俊
张亦俊
回复 @命名一直是个纠结的问题 : 我拿我自己的SQL SERVER试了一下,10000条1秒不到。MySQL的话,可能因为集合运算比较慢导致性能很差。
命名一直是个纠结的问题
命名一直是个纠结的问题
嗯 补充是我看了你的评论才加的,你所说的在数据库层做递归的确性能比较低,以为查询了 n此 加入 10000数据 递归 100次 就得扫描10000*100的数据 现在我们是把表里卖弄的10000条数据取出来 在程序里面做的递归 递归出来的 商家id (2,3,5,9,36,666....)
0
mark35
mark35

看了很多人都说左右值编码,想可不可以在 所有与商家关联的表如:市场用户,用户日志 等表里面加入商家的左右值
不可以。这样做不但违反范式并且会带来很大的麻烦。

就楼主需求,根本上还是数据库的问题。换掉mysql一了百了


命名一直是个纠结的问题
命名一直是个纠结的问题
话说啥范式啊 是不是关于数据库设计的?有没有相关教程
0
巴顿
巴顿
做过左右树编码+异步加载。可以对很多条数据有较好的支持。也就是点击哪个节点才去查找孩子节点返回来。不然对于上万条数据,左右树照样卡死。
0
巴顿
巴顿
就算是pid,id这样的设计,使用异步加载速度都是ok的,不要一次性全部加载出来,当然得先问需求。
返回顶部
顶部