我有一个关于数据库的理论问题。为了使它更具体,我想到了一个例子。
假设我有一个包含产品的商店。我有很多不同的产品。并非每种产品都具有相同的适用性。例如,我可以用千兆字节定义硬盘的大小,但不能在CPU上使用相同的属性,因为它不适用。我想要的是一个数据库,我可以动态地向产品添加属性。我能想出的唯一一件事就是:
一个带有ID,名称和描述的产品表。
一个具有ID,Product_ID,Property和Value的属性表。
通过这种方式,我可能会得到一个巨大的,我认为不那么高效的属性表。这已经困扰了我很长一段时间了。有谁知道我的问题更好的解决方案?
答案 0 :(得分:10)
这实际上正朝着第六范式转变,只是像你这样没有学术或经验背景的人不知道(a)名称和(b)规则和警告。这些人已经实现了通常所知的实体 - 属性 - 值或EAV。如果做得好,一切都很好,并且有数千个医疗系统在那里携带诊断和剂量信息。如果不是,则使用和维护一只狗的早餐。
首先确保您拥有真实且完整的5NF Product
。
始终使用完整的声明参照完整性; CHECK
个约束和RULES
。
永远不要将所有内容放入一个带有VARCHAR()
值的表中。始终使用正确(适用)的数据类型。这意味着您将拥有多个表,每个DataType一个,并且不会失去控制或完整性。
同样,任何关联表(其中对另一个表[例如供应商]有多个引用)必须是分开的。
CHECK
约束和RULE
,以确保数据和参照完整性不会丢失。这意味着,例如:
CPUSpeed
列,该列存储在ProductDecimal
,CHECK
,表示其处于适当的值范围Product
组合的数据类型正确的每个子CHECK
表ProductType-ColumnNo
保留Product
中的所有必填列;仅将sub-Product
表用于可选列。
对于每个这样的(例如Product
)表,您需要创建一个View(虚线),它将构建EAV / 6NF表中的5NF行。您可能有多个观看次数:Product_CPU
,Product_Disk
。
请勿通过视图进行更新。在存储过程中保持所有更新的事务性,并插入或更新每个列(即适用于每个特定Product
的{{1}}和sub-Product
表)。
巨大的?商业数据库(不是免费软件)对大型表或联接没有问题。这实际上是一个非常有效的结构,并允许非常快速的搜索,因为这些表实际上是面向列的(不是面向行的)。如果人口巨大,那么它是巨大的,做你自己的算术。
您还需要一个表,ProductType
(或属性)的查找表。这是目录的一部分,基于Property
更好的解决方案是获得完整,正式的第六范式。如果只有一个或几个表需要可选列,则不需要。
要明确:
第六范式该行包含主键,最多包含一个属性。
这是6NF(至少对于Product表集群),然后再按DataType再次标准化(不是在Normal Form意义上),以减少表的数量(否则每个属性将有一个表)。
这保留了完整的Rdb控制(FK,约束等);而常见的EAV类型并不需要DRI和控制。
这也有目录的基础。
<强> Link to Product Cluster Data Model 强>
那些不熟悉关系建模标准的人您可能对此▶5NF 6NF Discussion◀感兴趣。我会在某个时候写出来。
答案 1 :(得分:0)
最初我建议你有一个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))
当然,属性值可能很复杂而不是简单的字符串或整数,但希望这会带你走向正确的方向。