如何为每种产品具有许多参数的多种产品设计产品表


140

我在表格设计方面没有太多经验。我的目标是创建一个或多个满足以下要求的产品表:

  • 支持多种产品(电视,电话,PC等)。每种产品都有一组不同的参数,例如:

    • 手机将具有颜色,尺寸,重量,操作系统...

    • PC将具有CPU,HDD,RAM ...

  • 参数集必须是动态的。您可以添加或编辑所需的任何参数。

没有每种产品的单独表,如何满足这些要求?

Answers:


233

您至少具有以下五个选项来为您描述的类型层次结构建模:

  • 单表继承:所有产品类型的一个表,具有足够的列以存储所有类型的所有属性。这意味着有很多列,其中大多数列在任何给定行上都是NULL。

  • 类表继承:用于产品的一个表,存储所有产品类型共有的属性。然后,每个产品类型一个表,存储特定于该产品类型的属性。

  • 具体表继承:没有用于常见产品属性的表。相反,每种产品类型一个表,既存储通用产品属性又存储特定于产品的属性。

  • 序列化LOB:一个产品表,存储所有产品类型共有的属性。额外的一列以XML,YAML,JSON或其他格式存储了半结构化数据的BLOB。该BLOB允许您存储特定于每种产品类型的属性。您可以使用精美的设计模式对此进行描述,例如Facade和Memento。但是,无论您是否拥有一堆无法在SQL中轻易查询的属性;您必须将整个Blob取回应用程序并在那里进行排序。

  • Entity-Attribute-Value:一张产品表,一张表将属性转为行而不是列。就关系范式而言,EAV并不是有效的设计,但是无论如何,许多人仍在使用它。这是另一个答案提到的“属性模式”。有关某些陷阱,请参见在StackOverflow上使用eav标签的其他问题。

我在“ 可扩展数据建模”演示文稿中对此进行了详细介绍。


关于EAV的其他想法:尽管许多人似乎都喜欢EAV,但我不赞成。这似乎是最灵活的解决方案,因此也是最好的。但是,请记住格言TANSTAAFL。以下是EAV的一些缺点:

  • 无法将列设为必填项(等于NOT NULL)。
  • 无法使用SQL数据类型来验证条目。
  • 无法确保属性名称拼写一致。
  • 无法将外键放在任何给定属性的值上,例如用于查找表。
  • 传统表格格式的获取结果既复杂又昂贵,因为要从多个行中获取属性,您需要JOIN对每个属性进行处理。

EAV的灵活性程度使您需要在其他方面做出牺牲,这可能使您的代码变得比以更传统的方式解决原始问题要复杂(或更糟)。

在大多数情况下,没有必要具有这种程度的灵活性。在OP有关产品类型的问题中,为每种产品类型的产品特定属性创建一个表要简单得多,因此,至少对于相同产品类型的条目,您必须实施一些一致的结构。

仅在必须允许每一行都可能具有不同的属性集的情况下,才使用EAV 。当您拥有一组有限的产品类型时,EAV会显得过大。类表继承将是我的首选。


2019年更新:我看到人们使用JSON作为解决“许多自定义属性”问题的解决方案的次数越多,我越不喜欢该解决方案。即使使用特殊的JSON函数来支持查询,它也会使查询过于复杂。与存储在普通行和列中相比,存储JSON文档需要更多的存储空间。

基本上,在关系数据库中,这些解决方案都不是简单有效的。具有“可变属性”的整个想法与关系理论根本上是不一致的。

什么它归结为是,你要选择的解决方案,在此基础上是最不坏的一个你的应用程序。因此,在选择数据库设计之前,您需要知道如何查询数据。无法选择一种“最佳”解决方案,因为任何一种解决方案对于给定的应用程序可能都是最佳的。


11
@HimalayaGarg选项“ 4.5”确实与Bill的观点相反。
user3308043 2014年

2
与MySQL不同,SQL Server对XML,XPath和XQuery具有广泛的支持。因此,对于SQL Server用户而言,最好的选择是将额外的属性存储在XML类型的列中(选项4)。这样,您不必“将整个Blob取回应用程序并在那里进行排序”。您甚至可以在SQL Server中的XML列上创建索引。
Delphi.Boy 2014年

1
@ Delphi.Boy,很好的提示!Oracle还支持XML索引IBM DB2还支持索引XML
比尔·卡温

2
我更喜欢序列化LOB。但是它适合ORM吗?我使用EF。
Mahmood Jenami

@ user2741577,当然,但是您可能必须编写自定义代码才能从LOB解压缩非结构化数据的字段并将其应用于ORM对象的每个实体字段。我不了解EF,但是我想您可以创建一个执行此操作的基本ORM类。您需要跟踪哪些字段来自数据库行的具体字段,哪些字段来自LOB的字段,因此可以在需要保存对象时重新构建LOB。
比尔·卡温

12

@铁石心肠

我会一直使用EAV和MVC。

@比尔·卡文

以下是EAV的一些缺点:

  • 无法使列成为强制列(等效于NOT NULL)。
  • 无法使用SQL数据类型来验证条目。
  • 无法确保属性名称拼写一致。
  • 无法将外键放在任何给定属性的值上,例如用于查找表。

您在这里提到的所有这些内容:

  • 数据验证
  • 属性名称拼写验证
  • 必填列/字段
  • 处理从属属性的破坏

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

在我看来,以这种方式使用数据库就像用石头砸钉子一样。您可以用岩石来做,但是您不是要使用更精确且专门针对此类活动设计的锤子吗?

传统的表格布局获取结果非常复杂且昂贵,因为要从多个行中获取属性,您需要对每个属性进行JOIN。

可以通过对部分数据进行少量查询并将其处理为应用程序的表格布局来解决此问题。即使您有600GB的产品数据,如果您需要该表中每一行的数据,也可以批量处理。

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

您甚至不必担心额外数据存储的成本,因为它每天变得越来越便宜。

如果您仍然担心应用程序执行的操作的性能,则可以始终使用Erlang,C ++,Go语言对数据进行预处理,之后再在主应用程序中进一步处理优化后的数据。


you can always use Erlang, C++, Go Language to pre-process the data你什么意思?代替DB,使用Go lang?您能详细说明一下吗?
2016年

1
我完全同意。EAV是一种可行的方法,特别是如果您需要一定程度的灵活性,而这种灵活性允许您在不更改数据库模式的情况下添加新的产品和参数,我的意思是通过您的应用程序投入生产。去过也做过。为我工作。关于慢查询...这里有没有人听说过缓存?;)
pawel.kalisz

@Green我已经编辑了最后一段,以使其更加清楚,但这是关于将原始EAV数据以一种可以将数据转换,树形结构或任何基本映射中的内容处理到一种语言的过程传递给流程的,从而真正地快速地减少了操作并以内存有效的方式。具体细节取决于需要优化的内容
Pawel Barcik '17

6

如果我使用Class Table Inheritance意思:

一个产品表,存储所有产品类型共有的属性。然后,每个产品类型一个表,存储特定于该产品类型的属性。-比尔·卡温(Bill Karwin)

我最喜欢Bill Karwin的“建议”。我可以预见一个缺点,我将尝试解释如何避免成为问题。

当一种属性仅对1种类型通用,然后对2种,3种通用,等等,我应该制定什么应变计划?

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

如果我们出售家具,我们可能会出售椅子,灯具,沙发,电视等。电视可能是我们携带的唯一具有功耗的类型。因此,我会将power_consumption属性放在上tv_type_table。但是随后我们开始携带也具有power_consumption特性的家庭影院系统。好的,它只是另一种产品,所以我也将其添加到该字段中,stereo_type_table因为这可能是目前最简单的。但是随着时间的流逝,随着我们开始携带越来越多的电子产品,我们意识到power_consumption它应该足够广泛main_product_table。我现在应该怎么办?

将字段添加到中main_product_table。写一个脚本通过电子回路,并从每个就把正确的值type_tablemain_product_table。然后从每个列中删除该列type_table

现在,如果我一直使用相同的GetProductData类与数据库进行交互以获取产品信息;那么,如果现在需要重构代码中的任何更改,则这些更改应仅适用于该类。


3

您可以具有一个Product表和一个单独的ProductAdditionInfo表,该表具有3列:产品ID,附加信息名称,附加信息值。如果许多(但不是全部)产品都使用了颜色,则可以将其作为Product表中的可为空列,或者仅将其放入ProductAdditionalInfo中。

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

史蒂夫·耶格(Steve Yegge)将其称为“属性”模式,并撰写了一篇有关使用该模式的长篇文章。


4
属性模式只是实体名称的另一个名称。它被广泛使用,但是将其存储在关系数据库中会破坏规范化规则。
比尔·卡文

2
老实说,当我在@Bills答案中阅读EAV的描述时,我不太明白他在解释什么。但是当你说3 columns: product ID, additional info name, additional info value我理解这个概念时。而且我实际上以前已经做过,并且遇到了问题。但是,我现在不记得这些问题是什么。
JD Isaacks

1
@JDIsaacks在这种模式下,一个常见的问题是我们不知道需要多少个JOIN来获取所有属性。
2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.