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

foxidea 发布于 2012/08/06 09:44
阅读 6K+
收藏 7

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

数据库表结构是这样的:

[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)

这样做实在是太糟糕了

 


那么该怎么设计呢?

加载中
1
Andre.Z
Andre.Z

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

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

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

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

424
424
回复 @零度C : 学习学习
卖豆浆不卖油条
卖豆浆不卖油条
野鬼说得很有道理,就像java的各种数据类型都有一个边界一样
1
宏哥
宏哥

都 TMD  mysql 下的蛋

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

z
zippon
回复 @mark35 : PG跟着Oracle走的,感觉和office跟wps的关系一样。Oracle在版本4.x还是5.x的时候就有这个了,猛。
mark35
mark35
回复 @zippon : oracle强是当然的,pg也有这个才是真强
宏哥
宏哥
回复 @zippon : 我还以为其他数据库都有类似玩意,PG也有
z
zippon
查了半天,学习了下connect by。 这还真不算mysql的蛋。SQL Server, DB2, Sybase 都没有比较容易的hierarchical query 原生支持。连SQL标准里只规定了RCTE(recursive common table expression)。 只能说Oracle太强了...
0
紅顏為君笑
紅顏為君笑
再添加一个字段 作为 标识  例如:字段 state 男装:1 女装 :0 
0
笨蛋EGG
笨蛋EGG
数量很大的话,才能看出效率问题吧····
0
笨蛋EGG
笨蛋EGG
能不能把分类条件分开来查询,该分类字段整个索引,用临时表拼加结果··这样条件查询就可以用=·····大数据量下=和in的差别就比较明显··
0
魔力猫
魔力猫
只要数据库本身支持递归,再有索引帮忙,效率不会差的。
0
黄龍
黄龍
我们公司也有张表是这样设计的 ~ oracle用start with ... connect by 查询效率还可以!
0
xyz555
xyz555
这种无限级分类优点是灵活,网站的分类往往是不确定的,不是说我今天最多10级,明天一定不会有11、12个级别。缺点当然就是效率差。要兼顾的话可能就是将分级载入内存(NoSQL?)或更为廉价的方法作为cache写入一个文件。这样减少查数据库的次数。
0
deleted
deleted
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都能很轻松的实现
返回顶部
顶部