我正在更新我们网站的产品数据库。它内置于MySQL中,但这更多是一个通用的数据库设计模式问题。
我打算切换到Supertype / Subtype模式。我们当前/以前的数据库主要是一个表,其中包含有关一种产品类型的数据。我们正在考虑将我们的产品范围扩展到包括不同的产品。
这个新的草稿设计是这样的:
Product product_[type] product_attribute_[name]
---------------- ---------------- ----------------------------
part_number (PK) part_number (FK) attributeId (PK)
UPC specific_attr1 (FK) attribute_name
price specific_attr2 (FK)
... ...
我对产品属性表有疑问。这里的想法是产品可以具有给定属性的列表,例如颜色:红色,绿色,蓝色或材料:塑料,木材,铬,铝等。
该列表将存储在表中,并且该属性项的主键(PK)将在特定产品表中用作外键(FK)。
(Martin Fowler的书《企业应用程序体系结构的模式》称为“ 外键映射 ”)
这允许网站界面提取给定属性类型的属性列表,并将其吐入下拉选择菜单或其他UI元素中。该列表可以视为属性值的“授权”列表。
对我而言,拉出特定产品时最终发生的连接数量过多。您必须将每个产品属性表都连接到产品,以便获得该属性的字段。通常,该字段的名称可能仅仅是字符串(varchar)。
这种设计模式最终会创建大量表,并且最终会为每个属性提供一个表。解决此问题的一种方法是为所有产品属性创建更多的“抓包”表。像这样:
product_attribute
----------------
attributeId (PK)
name
field_name
这样,您的表可能如下所示:
1 red color
2 blue color
3 chrome material
4 plastic material
5 yellow color
6 x-large size
这可以帮助减少表的蠕变,但不会减少联接的数量,将这么多不同的类型组合到一个表中感觉有点不对。但是您将能够轻松获得所有可用的“颜色”属性。
但是,可能有一个属性具有比“名称”更多的字段,例如颜色的RGB值。这将要求该特定属性可能具有另一个表或对name:value对使用单个字段(这有其自身的缺点)。
我能想到的最后一个设计模式是将实际属性值存储在特定产品表中,而根本没有“属性表”。像这样:
Product product_[type]
---------------- ----------------
part_number (PK) part_number (FK)
UPC specific_attr1
price specific_attr2
... ...
它会包含实际值,而不是另一个表的外键:
part_number color material
----------- ----- --------
1234 red plastic
这将消除联接并防止表蠕变(也许?)。但是,这会阻止具有属性的“授权列表”。您可以返回给定字段(例如颜色)的所有当前输入值,但这也消除了给定属性具有“授权列表”值的想法。
要获得该列表,您仍然必须创建一个“垃圾袋”属性表,或者为每个属性创建多个表(表蠕变)。
这带来了更大的缺点(以及为什么我从未使用过这种方法),现在在多个位置使用了产品名称。
如果您在“主属性表”中具有“红色”的颜色值并将其存储在“ product_ [type]”表中,则对“主”表的更新将导致潜在的数据完整性问题,如果应用程序没有也不要使用“ product_type”表中的旧值更新所有记录。
因此,在我对这种情况进行了漫长的解释和分析之后,我意识到这不是一个罕见的情况,甚至可能为这种情况命名。
是否有普遍接受的解决方案来应对这一设计挑战?如果表相对较小,是否可能接受大量的联接?在某些情况下,是否可以接受属性名称而不是属性PK?我是否还在考虑其他解决方案?
有关此产品数据库/应用程序的一些注意事项:
- 产品不经常更新/添加/删除
- 属性不经常更新/添加/删除
- 经常查询该表以读取/返回信息
- 服务器端缓存已启用,可以缓存给定查询/结果的结果
- 我计划仅从一种产品类型开始,随着时间的推移扩展/添加其他产品类型,并且可能会有10多种不同类型