27
回答
关于无限级分类数据库表结构设计问题,遍历某分类下所有产品 效率

 关于无限级分类数据库表结构设计问题,遍历某分类下所有产品 效率

数据库表结构是这样的:

[Category] 类别表

Id(int) 类别Id
ParentId(int) 父类Id
Name(nvarchar(50)) 类别名称


[Product] 产品表

Id(int) 产品名称
Name(nvarchar(50)) 产品名称
CategoryId(int) 类别Id(对应 [Category].Id)
Info(ntext) 介绍信息
……

 

 

[Category] 类别表数据
Id   ParentId     Name

1   0         服装
2   1         男装
3   2         衬衫
4   2         长裤
5   2         短裤
6   2         T恤
7   2         外套
8   2         卫衣
9   2         西装
10   4          休闲裤
11   4          西裤
12   4          牛仔裤
13   4          运动裤

 

 

 


[Product] 产品表数据 不再一一举例
Id   Name   CategoryId   Info

2
3
……

 


这样设计的结构,存在很严重的效率问题,
假设我想找出某分类(假设为男装)下所有的产品,就需要用递归算法,找出(男装)下的所有子分类,然后对 产品表进行 条件 in 查询,得到产品列表

 

找出所有男装产品

首先写程序,递归出 男装分类下的子类列表(2,3,4,5,6,7,8,9,10,11,12,13)

然后用 sql 查询出来

select * from [Product] where CategoryId in(2,3,4,5,6,7,8,9,10,11,12,13)

这样做实在是太糟糕了

 


那么该怎么设计呢?

<无标签>
举报
foxidea
发帖于6年前 27回/6K+阅
共有27个答案 最后回答: 4年前

类别表加一个字段,存放类别路径,假设为path,,值可以根据算法出,也可以人工输入。
比如衬衫为/2/3/,长裤为/2/4/,短裤/2/5/,休闲裤为/2/4/10/ 。。。
查找出子类,只要一条查询语句就完事了,还没有递归。
空间换时间的做法。
无限级分类还用递归,那是自己找麻烦。

--- 共有 22 条评论 ---
C_Guy你好,先抱歉挖坟了。关于这个问题,我觉得你的方法能提高遍历分类下对应产品的效率,但是还有个问题,要把分类全部按层级遍历列出来是否还是得用递归? 3年前 回复
弦歌哈哈。我把@那里看反了,你们是互相@对方,我把@后面的当作发帖人了,非常sorry!看了你后面的回复,Andre.Z思路是正确的。很清晰!我在一个项目里就是类似的用法,但是还不如你的简洁,也给我一些启示。 6年前 回复
Andre.Z回复 @weihuang : 拜托,请你搞清楚对象,是我说的增加一个字段吧,用于辅助吧。 6年前 回复
弦歌@Andre.Z 请看清了再说话,@xyz555是说“增加”一个path字段,用于辅助pid来显示各级菜单,避免每次显示菜单都做很多层的嵌套递归。而不是说把pid改成path。也没有说不要pid字段。 如果要删除某个类下的子类。这个时候做多层嵌套的递归应该问题不大。因为删除操作是非常少见的操作;显示菜单操作是非常频繁的操作,就可以使用辅助手段来节省资源消耗! 6年前 回复
Andre.Z回复 @xyz555 : sql替换字符串会不,子类前面的字符串就是父类的那个值,我只能说到这里了。惹不起你,我躲行了吧。别回我了,谢谢。 我闪了。 6年前 回复

无限级分类本身就是找麻烦。如楼上说的,还要用递归,就更胡扯了。我是做算法优化的,我可以给你点我的专业角度的意见。任何系统,在没动手前就要规划目标。规划目标之一的任务就是确定系统边界。例如我最大支持多少,最快我能跑多少,等等。

只要是数字计算机,就没有无限这个概念。

--- 共有 2 条评论 ---
424回复 @零度C : 学习学习 3年前 回复
卖豆浆不卖油条野鬼说得很有道理,就像java的各种数据类型都有一个边界一样 6年前 回复

都 TMD  mysql 下的蛋

在PG,oracle里面,直接 connect by 就啥屁事没有

--- 共有 4 条评论 ---
zippon回复 @mark35 : PG跟着Oracle走的,感觉和office跟wps的关系一样。Oracle在版本4.x还是5.x的时候就有这个了,猛。 6年前 回复
mark35回复 @zippon : oracle强是当然的,pg也有这个才是真强 6年前 回复
宏哥回复 @zippon : 我还以为其他数据库都有类似玩意,PG也有 6年前 回复
zippon查了半天,学习了下connect by。 这还真不算mysql的蛋。SQL Server, DB2, Sybase 都没有比较容易的hierarchical query 原生支持。连SQL标准里只规定了RCTE(recursive common table expression)。 只能说Oracle太强了... 6年前 回复
能不能把分类条件分开来查询,该分类字段整个索引,用临时表拼加结果··这样条件查询就可以用=·····大数据量下=和in的差别就比较明显··
这种无限级分类优点是灵活,网站的分类往往是不确定的,不是说我今天最多10级,明天一定不会有11、12个级别。缺点当然就是效率差。要兼顾的话可能就是将分级载入内存(NoSQL?)或更为廉价的方法作为cache写入一个文件。这样减少查数据库的次数。
db只做持久化好了, 数据从cache里取, 比如

categories_version:$version
category:$version:$category_id


分类数据变动的时候, 扔给后台进程加锁,取version = categories_version+1,  重新生成所有category:$version:$category_id
这期间web端获取的还是旧的version数据
后台进程生成完新缓存刷新categories_version, 再清理旧的category:$version:$category_id


至于搜索, 更好办了, 何必和sql数据库过不去

如果一个东西属于分类3, 3是2的子分类,2是1的子分类, 那document相应category field存成1,2,3好了,无论搜哪个都能搜到

lucene,xapian都能很轻松的实现
顶部