如何为每种产品有多个参数的多种产品devise产品表

我没有太多的桌面devise经验。 我的目标是创build一个或多个满足以下要求的产品表:

  • 支持多种产品(电视,电话,个人电脑,…)。 每种产品都有一组不同的参数,如:

    • 手机将有颜色,大小,重量,操作系统…

    • PC将有CPU,硬盘,RAM …

  • 这组参数必须是dynamic的。 您可以添加或编辑您喜欢的任何参数。

我怎样才能满足这些要求,没有一个单独的表格,每种产品?

您至less有以下五种选项可用于对您描述的types层次结构进行build模:

  • 单表inheritance :所有产品types都有一个表,并有足够的列来存储所有types的所有属性。 这意味着很多列,大多数列在任何给定的行上都是NULL。

  • 类表inheritance :产品的一个表,存储所有产品types通用的属性。 然后每个产品types一个表,存储特定于该产品types的属性。

  • 混凝土表inheritance :没有常见商品属性的表。 相反,每个产品types一个表,存储常用产品属性和产品特定属性。

  • 序列化的LOB :产品的一个表,存储所有产品types通用的属性。 一个额外的列存储XML,YAML,JSON或其他格式的半结构化数据的BLOB。 该BLOB允许您存储特定于每个产品types的属性。 你可以使用花哨的devise模式来描述这个,比如Facade和Memento。 但是,不pipe你在SQL中是否有一堆不容易查询的属性, 你必须把整个blob取回到应用程序,并在那里进行分类。

  • 实体属性值 :产品的一个表,以及一个将属性赋予行而不是列的表。 EAV在关系范式方面不是一个有效的devise,但很多人仍然使用它。 这是另一个答案提到的“属性模式”。 使用StackOverflow上的eav标签查看其他问题,了解一些缺陷。

我在一个演示文稿“ 可扩展数据build模” ( Extensible Data Modeling)中写了更多关于这方面的内容


关于EAV的其他想法:虽然很多人似乎都喜欢EAV,但我不知道。 这似乎是最灵活的解决scheme,因此是最好的。 但是,请记住坦率的坦率的说法 。 以下是EAV的一些缺点:

  • 没有办法使一个列强制(相当于NOT NULL )。
  • 没有办法使用SQL数据types来validation条目。
  • 没有办法确保属性名称拼写一致。
  • 没有办法将外键放在任何给定属性的值上,例如查找表。
  • 以传统的表格布局获取结果是复杂且昂贵的,因为要从多行获取属性,您需要为每个属性执行JOIN

灵活性的程度EAV给你在其他领域需要牺牲,可能使你的代码复杂(或更糟糕)比以原来的问题更传统的方式。

在大多数情况下,没有必要具有这种灵活性。 在OP关于产品types的问题中,为产品特定的属性创build每种产品types的表格要简单得多,因此至less对于相同产品types的条目,您必须执行一些一致的结构。

我只会使用EAV,如果每行必须被允许潜在地有一组不同的属性。 当你有一个有限的产品types时,EAV是矫枉过正的。 类表inheritance将是我的第一select。

@铁石心肠

我会一路去EAV和MVC。

@卡尔文

以下是EAV的一些缺点:

 No way to make a column mandatory (equivalent of NOT NULL). No way to use SQL data types to validate entries. No way to ensure that attribute names are spelled consistently. No way to put a foreign key on the values of any given attribute, eg 

查找表。

所有你在这里提到的东西:

  • 数据validation
  • 属性名称拼写validation
  • 强制性列/字段
  • 处理依赖属性的破坏

在我看来,根本不属于数据库,因为没有一个数据库能够像应用程序的编程语言那样在适当的层面上处理这些交互和需求。

在我看来,以这种方式使用数据库就像用石头敲钉子一样。 你可以用一块石头做到这一点,但是你不应该使用一个更加精确和专门为这种活动devise的锤子吗?

以传统的表格布局获取结果是复杂且昂贵的,因为要从多行获取属性,您需要为每个属性执行JOIN。

这个问题可以通过对部分数据进行less量的查询,并用你的应用程序将它们处理成表格式来解决。 即使您有600GB的产品数据,如果您需要此表中每行的数据,也可以批量处理。

进一步如果您想提高查询的性能,您可以select某些操作,例如报告或全局文本search,并为它们准备索引表,这些索引表可以存储所需的数据,并且会定期重新生成,例如每30分钟一次。

您甚至不需要关心额外数据存储的成本,因为它每天都变得更便宜,更便宜。

如果您仍然关心应用程序执行的操作的性能,那么您总是可以使用Erlang,C ++,Go Language预处理数据,稍后在主应用程序中进一步处理优化的数据。

如果我使用Class Table Inheritance含义:

产品一张表,存储所有产品types通用的属性。 然后每个产品types一个表,存储特定于该产品types的属性。 – 凯尔文

我喜欢比尔·卡尔文最好的build议..我可以预见一个缺点,我将试图解释如何避免成为一个问题。

当只有一种共同的属性,然后在2,3等共同的属性时,应该有什么应急计划?

例如:(这只是一个例子,不是我真正的问题)

如果我们销售家具,我们可能会出售椅子,灯具,沙发,电视机等。电视机型号可能是我们唯一携带的具有耗电量的types。 所以我会把power_consumption属性放在tv_type_table 。 但是接下来我们开始携带同样具有power_consumption属性的家庭影院系统。 确定它只是一个其他的产品,所以我会把这个领域添加到stereo_type_table ,因为这可能是最简单的。 但随着时间的推移,我们开始携带越来越多的电子产品,我们意识到power_consumption足够广泛,应该在main_product_table 。 我现在应该怎么做?

将该字段添加到main_product_table 。 写一个脚本循环通过电子设备,并把每个type_table的正确值type_tabletype_table 。 然后从每个type_table删除该列。

现在,如果我总是使用相同的GetProductData类来与数据库进行交互来提取产品信息, 那么如果现在代码中的任何变化都需要重构,那么它们应该仅仅是那个类。

您可以有一个产品表和一个单独的ProductAdditionInfo表,其中包含3列:产品ID,附加信息名称,附加信息值。 如果许多但不是所有types的产品都使用颜色,则可以将其设置为Product表中的可为空列,或者将其放入ProductAdditionalInfo中。

这种方法不是关系数据库的传统技术,但是我已经看到它在实践中使用了很多。 它可以是灵活的,有良好的性能。

Steve Yegge把这个叫做Properties模式,并写了一个关于使用它的长篇文章。