数据库架构相关问题

4

我有一个关于数据库的理论问题。为了让它更具体,我想出了一个例子。

假设我有一个产品商店,里面有很多不同的产品。并非每种产品都具有相同的属性。例如,我可以定义硬盘的大小(以GB为单位),但不能将同样的属性用于CPU,因为它不适用。我想要一个可以动态添加产品属性的数据库。我能想到的唯一方法是:

一个产品表,包括ID、名称和描述。

一个属性表,包括ID、产品ID、属性和值。

这样,我可能会得到一个巨大的、不太高效的属性表。这个问题困扰我已经很长时间了。有没有人知道更好的解决方案?


1
如果您完全不知道可能的属性集是什么样子,那么您的动态方案确实可以工作。但这会带来问题,因为您需要保持可能的属性一致(这样您就不会出现多个属性表示同一件事情,例如“memory_size”,“gigabytes”,“bytes”等)。另一种选择是,如果您知道属性可能是什么,可以拥有一系列专门的表格,例如StorageProducts、ProcessingProducts等,它们包含适用于各种产品类别的属性。 - John Pickup
@John Pickup:为什么不把你那个好答案放到一个回答里呢?我会投票支持它,它是对PerformanceDBA答案的很好补充。 - iDevlop
2个回答

12

这实际上是朝着第六范式(6NF)发展,只是像你这样没有学术或经验背景的人不知道(a)它的名称和(b)规则和注意事项。这些人实现了通常被称为实体-属性-值(EAV)的东西。如果做得正确,那就没问题了,有成千上万的医疗系统在其中使用这种表格来携带诊断和剂量信息。如果做得不好,那么使用和维护起来就会很麻烦。

  1. 首先确保您在真正和完整的第五范式(5NF)中拥有Product

  2. 始终使用全声明性参照完整性; CHECK限制和RULES

  3. 永远不要将所有内容都放入一个具有用于值的VARCHAR()的表中。始终使用正确的(适用的)数据类型。这意味着您将有几个表,每个数据类型一个表,这样就不会失去控制或完整性。

  4. 同样,任何关联表(其中有对另一张表[例如供应商]的多重引用)必须是单独的。

    • 我提供了一个具有完整控制性的数据模型;它包括可以用于验证和导航的简单目录。您需要添加每个CHECK约束和RULE,以确保不会丢失数据和参照完整性。这意味着例如:
      • 对于存储在ProductDecimal 中的CPUSpeed列,请CHECK其是否在适当的值范围内
      • 对于每个子Product表,请CHECK ProductType-ColumnNo组合的数据类型是否正确
    • 这种结构比大多数EAV更好,但并非完全6NF。
      .
  5. Product表中保留所有必需列;只在sub-Product表中使用可选列。

  6. 针对每个这样的(例如Product)表,您需要创建一个视图(虚线),该视图将从EAV / 6NF表中构建5NF行。您可以拥有多个视图:Product_CPUProduct_Disk等。

  7. 不要通过视图进行更新。将所有更新置于存储过程中,并为每个特定ProductType逐个插入或更新每个列(即适用于Product子Product表的列)。

  8. 巨大?商业数据库(而不是免费软件)在处理大表或联接时没有任何问题。实际上,这是一种非常高效的结构,并且由于表实际上是面向列的(而不是面向行的),因此允许非常快速的搜索。如果人口众多,则它就是巨大的,请自行计算。

  9. 您需要另外一个表,即Property(或属性)的查找表。这是目录的一部分,并基于ProductType

更好的解决方案是采用完全正式的第六范式。如果只有一个或少数需要可选列的表,则不必这样做。

明确一点:

  • 第六范式是行由主键和最多一个属性组成。

  • 这是6NF(至少适用于Product表集群),然后再次按数据类型进行规范化,以减少表的数量(否则每个属性将对应一个表)。

  • 这保留了完整的Rdb控制(外键、约束等);而常见的EAV类型则不关心DRI和控制。

  • 这也具有目录的基础。

产品群集数据模型链接

IDEF1X符号链接适用于那些不熟悉关系建模标准的人。

更新

你可能会对这个▶5NF 6NF讨论◀感兴趣。我会在某些时候写出来。


2
我对你详尽的回答感到惊讶。非常感谢!作为一名Web开发人员,我注意到自己的知识存在巨大的空白。作为一名IT学生,我想更多地了解这个主题。你知道有什么好的文献可以供我深入研究吗? - Bram Jetten
1
@Bram。谢谢,不客气。大学毕业后,我有很好的导师,那是最快的方式。Rdb设计与应用程序设计不同。跟随有实际经验的人。购买最好的教科书。网络充满了错误和肤浅的信息,许多回答者从中阅读并发布。确保你做出区分。保持开放的心态,但不要太开放以至于充满垃圾。对标准要严格,它们是由比我们更伟大的头脑创造的。如果您转到我的链接中的目录,您可以查看其他答案。提出好问题。 - PerformanceDBA
1
@Bram。为了比较和进一步理解,请查看此问题/答案,以获取不同的6NF版本。 - PerformanceDBA

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

当然,属性值可能是复杂的而不仅仅是简单的字符串或整数,但希望这能让您朝着正确的方向前进。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接