电子商务,类别和类别浏览产品

时间:2009-10-29 03:03:36

标签: php database-design e-commerce

我正在为客户建立一个EC网站,项目经理带来了一些奇怪的想法,我正在努力实际实现他卖给客户的东西。

这是我的主要问题,并简要概述了系统的设置方式:产品属于类别,类别可能是另一类别的子类。因此,该类别在网站的左侧边栏中显示为树。

用户可以浏览任何类别,甚至是非“叶子”类别,如果用户点击非叶类别,那么应该在1级类别上呈现类似的列表(同样适用于2级类别):

big category 1
 category level ( 3 or 2 )
  product 1
  product 2
  product 3
 category level ( 3 or 2 ) 

这些东西也应该有一些分页并在每个页面上显示5个产品。另外,类别应该以相同的方式排序,它们出现在左侧的菜单中......我的DB方案是这样的:

+-------------+    +-------------+
+ category    +    + product     +
+-------------+    +-------------+
+ category_id +    + product_id  +
+ parent_id   +    + category_id + 
+-------------+    +-------------+

我无法弄清楚我应该如何对SQL进行编码以确保产品按照它们的顺序显示(例如订购产品和类别的菜单)。

另外我担心整个设置的性能,如果用户选择非“叶子”类别,我将不得不搜索所有子类别并创建一个大类别IN(id1,id2,id3),我知道经验丰富的IN声明表现不佳。

如果有人遇到相同的设计/问题并且有一些建议如何制作,我将不胜感激。

2 个答案:

答案 0 :(得分:6)

您可以使用物化路径设计。目录路径是物化路径的示例。也就是说,一系列的祖先值连接在一起,其中一些字符(“/”或“,”是常见的)将它们分开。

所以你可能有类别:

+---------------------------------------------+
| cat_id | Name            | cat_path | depth |
+---------------------------------------------+
|    1   | Electronics     | 1/       |   1   |
|    2   | Digital cameras | 1/2/     |   2   |
|    3   | SLR cameras     | 1/2/3/   |   3   |
|    4   | Audio           | 1/4/     |   2   |
|    5   | Speakers        | 1/4/5/   |   3   |
|    6   | Wall Satellites | 1/4/5/6/ |   4   |
|    7   | Computers       | 1/7/     |   2   |
+---------------------------------------------+

现在,如果您想要所有音频产品,您可以执行以下查询:

SELECT p.*, pc.*
FROM Products p JOIN Categories pc ON (p.cat_id = pc.cat_id)
JOIN Categories c ON (pc.cat_path LIKE c.cat_path||'%')
WHERE c.name = 'Audio';

例如,'1/4/5/6' LIKE '1/4/%'为真,因此包含了Wall Satellites。对于Audio的任何其他子类别也是如此。


关于菜单渲染的问题:我假设你想要菜单渲染:   - 所选类别的所有祖先   - 所选类别祖先的所有兄弟姐妹

因此,如果您选择“演讲者”,您会看到:

  • 电子
    • 音频
      • 扬声器
    • 计算机
    • 数码相机

但你不想要电脑或数码相机的后代(即演讲者的“堂兄弟”)。

SELECT uncle.name, uncle.depth
FROM Categories chosen
JOIN Categories ancestor ON (chosen.cat_path LIKE ancestor.cat_path||'%')
JOIN Categories uncle ON (ancestor.depth = uncle.depth
  AND SUBSTRING(REVERSE(ancestor.cat_path), 3, 100) = SUBSTRING(REVERSE(uncle.cat_path), 3, 100))
WHERE chosen.name = 'Speakers'
ORDER BY uncle.depth, uncle.name;

我正在使用技巧来检测叔叔:在剥离最后一个元素后比较路径。为此,请反转字符串,然后剥离第一个元素。这应该至少在MySQL和MS SQL Server中起作用,但REVERSE()不是标准的,可能无法移植到其他品牌的RDBMS。

请注意,对于cat_path中的每个元素,您应该允许多个数字,在这种情况下,子字符串偏移量也应该增加。

答案 1 :(得分:1)

从性能角度来看,这是一个糟糕的设计。如果客户意外点击了最顶层的类别,您将执行整个库存的查询。这可能需要花费不可接受的时间。在网络术语中,这意味着客户失去耐心,点击您的竞争对手的网站,再也不会访问您的网站

当然,过早优化是所有邪恶的根本所有,但避免做完全愚蠢的事情是个好主意。

我也会将树导航的整个想法作为一种方法。要求你的客户玩一个“猜猜我们如何盘点我们的股票”的游戏,实在太过分了。除了其他任何东西,在许多领域中,产品可以属于多个类别,因此将它们装入层次结构中是一个任意的过程。至少你可能应该有一个数据模型,它支持将产品分配给多个叶子类别。 (这可能取决于您销售的产品的性质和类别的粒度)。

如果你的老板坚持自己的方式,那么你仍然有一些选择来提高查询的性能。例如,您可以拥有一个表,其中包含所有父类别加入的所有产品......

cat1 product1
cat1 product2
cat1 product3
cat1 product4
cat1 cat1.1 product1
cat1 cat1.1 product2
cat1 cat1.2 product3
cat1 cat1.2 product4
cat1 cat1.1 cat1.1.1 product1
cat1 cat1.1 cat1.1.2 product2
cat1 cat1.2 cat1.2.1 product3
cat1 cat1.2 cat1.2.2 product4

您必须通过触发器或作为物化视图或通过其他一些机制(取决于您的数据库风格提供的内容)来维护它。但是,与不必为每个客户查询重新组装产品层次结构的性能优势相比,维护它的开销可以忽略不计。此外,您的库存不太可能出现那么大的波动。