我有一个关于数据库的理论问题。为了让它更具体,我想出了一个例子。
假设我有一个产品商店,里面有很多不同的产品。并非每种产品都具有相同的属性。例如,我可以定义硬盘的大小(以GB为单位),但不能将同样的属性用于CPU,因为它不适用。我想要一个可以动态添加产品属性的数据库。我能想到的唯一方法是:
一个产品表,包括ID、名称和描述。
一个属性表,包括ID、产品ID、属性和值。
这样,我可能会得到一个巨大的、不太高效的属性表。这个问题困扰我已经很长时间了。有没有人知道更好的解决方案?
我有一个关于数据库的理论问题。为了让它更具体,我想出了一个例子。
假设我有一个产品商店,里面有很多不同的产品。并非每种产品都具有相同的属性。例如,我可以定义硬盘的大小(以GB为单位),但不能将同样的属性用于CPU,因为它不适用。我想要一个可以动态添加产品属性的数据库。我能想到的唯一方法是:
一个产品表,包括ID、名称和描述。
一个属性表,包括ID、产品ID、属性和值。
这样,我可能会得到一个巨大的、不太高效的属性表。这个问题困扰我已经很长时间了。有没有人知道更好的解决方案?
这实际上是朝着第六范式(6NF)发展,只是像你这样没有学术或经验背景的人不知道(a)它的名称和(b)规则和注意事项。这些人实现了通常被称为实体-属性-值(EAV)的东西。如果做得正确,那就没问题了,有成千上万的医疗系统在其中使用这种表格来携带诊断和剂量信息。如果做得不好,那么使用和维护起来就会很麻烦。
首先确保您在真正和完整的第五范式(5NF)中拥有Product
。
始终使用全声明性参照完整性; CHECK
限制和RULES
。
永远不要将所有内容都放入一个具有用于值的VARCHAR()
的表中。始终使用正确的(适用的)数据类型。这意味着您将有几个表,每个数据类型一个表,这样就不会失去控制或完整性。
同样,任何关联表(其中有对另一张表[例如供应商]的多重引用)必须是单独的。
CHECK
约束和RULE
,以确保不会丢失数据和参照完整性。这意味着例如:
ProductDecimal
中的CPUSpeed
列,请CHECK
其是否在适当的值范围内Product
表,请CHECK
ProductType-ColumnNo
组合的数据类型是否正确在Product
表中保留所有必需列;只在sub-Product
表中使用可选列。
针对每个这样的(例如Product
)表,您需要创建一个视图(虚线),该视图将从EAV / 6NF表中构建5NF行。您可以拥有多个视图:Product_CPU
、Product_Disk
等。
不要通过视图进行更新。将所有更新置于存储过程中,并为每个特定ProductType
逐个插入或更新每个列(即适用于Product
和子Product
表的列)。
巨大?商业数据库(而不是免费软件)在处理大表或联接时没有任何问题。实际上,这是一种非常高效的结构,并且由于表实际上是面向列的(而不是面向行的),因此允许非常快速的搜索。如果人口众多,则它就是巨大的,请自行计算。
您需要另外一个表,即Property
(或属性)的查找表。这是目录的一部分,并基于ProductType
。
更好的解决方案是采用完全正式的第六范式。如果只有一个或少数需要可选列的表,则不必这样做。
明确一点:
第六范式是行由主键和最多一个属性组成。
这是6NF(至少适用于Product表集群),然后再次按数据类型进行规范化,以减少表的数量(否则每个属性将对应一个表)。
这保留了完整的Rdb控制(外键、约束等);而常见的EAV类型则不关心DRI和控制。
这也具有目录的基础。
IDEF1X符号链接适用于那些不熟悉关系建模标准的人。
你可能会对这个▶5NF 6NF讨论◀感兴趣。我会在某些时候写出来。
最初我建议你有一个productproperty
表来模拟产品和属性之间的关系。这样可以让你将许多产品与特定属性关联起来。
然而,我不太喜欢每个属性旁边都保存一个值的1:1的想法。如果你有一个propertyvalue
表关联一个属性和一个值会更好一些。然后,你可以放弃productproperty
表,采用更丰富的productpropertyvalue
表来完全描述产品、它的属性及其值之间的关系。
也许你可以有以下内容:
product => (ID (unique key), Name, Description)
property => (ID (unique key), Description)
propertyvalue => (ID (unique key), propertyID (foreign key), value)
productpropertyvalue => (ID (unique key), productID (foreign key), propertyValueID (foreign key))