如何为每种产品都有很多参数的多种产品设计产品表

Sto*_*art 127 database-design relational-database database-schema

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

  • 支持多种产品(电视,手机,PC,......).每种产品都有不同的参数集,例如:

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

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

  • 参数集必须是动态的.您可以添加或编辑您喜欢的任何参数.

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

Bil*_*win 216

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

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

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

  • 具体表继承:没有常用Products属性的表.而是每个产品类型一个表,存储常见的产品属性和特定于产品的属性.

  • 序列化LOB:一个产品表,存储所有产品类型共有的属性.一个额外的列以XML,YAML,JSON或其他格式存储半结构化数据的BLOB.此BLOB允许您存储特定于每种产品类型的属性.您可以使用精美的设计模式来描述这一点,例如Facade和Memento.但是,无论你有多少属性都无法在SQL中轻松查询; 你必须将整个blob提取回应用程序并将其排序.

  • 实体 - 属性 - 值:一个用于Products的表,一个用于将属性转换为行而不是列的表.EAV在关系范式方面不是一个有效的设计,但无论如何许多人都使用它.这是另一个答案提到的"属性模式".有关一些陷阱,请参阅StackOverflow上带有eav标记的其他问题.

我在演示文稿" 可扩展数据建模"中写了更多关于此内容的文章.


关于EAV的其他想法:虽然许多人似乎更喜欢EAV,但我没有.它似乎是最灵活的解决方案,因此也是最好的解决方案.但是,请记住格言TANSTAAFL.以下是EAV的一些缺点:

  • 无法强制列(相当于NOT NULL).
  • 无法使用SQL数据类型来验证条目.
  • 无法确保属性名称拼写一致.
  • 无法将外键放在任何给定属性的值上,例如查找表.
  • 在传统的表格布局中获取结果既复杂又昂贵,因为要从JOIN每个属性中获取多行的属性.

EAV给你的灵活程度需要在其他方面做出牺牲,可能会使你的代码变得复杂(或更糟),而不是以更传统的方式解决原始问题.

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

只有在必须允许每一行可能具有一组不同的属性时才使用EAV .如果您拥有一组有限的产品类型,EAV就会过度.类表继承将是我的第一选择.

  • @HimalayaGarg选项"4.5"确实与Bill的帖子完全相反. (10认同)
  • 与MySQL不同,SQL Server广泛支持XML,XPath和XQuery.因此,对于SQL Server的用户,最好的选择是将额外的属性存储在XML类型的列中(选项4).这样你就不必"将整个blob提取回应用程序并将其排序." 您甚至可以在SQL Server中的XML列上创建索引. (2认同)
  • @Delphi.Boy,很棒的提示![Oracle 还支持索引 XML](http://docs.oracle.com/cd/B28359_01/appdev.111/b28369/xdb_indexing.htm#CHDJECDA)。[IBM DB2 还支持索引 XML](http://www.ibm.com/developerworks/data/library/techarticle/dm-0611nicola/)。 (2认同)
  • 我更喜欢Serialized LOB.但它适合ORM吗?我用EF. (2认同)

Paw*_*cik 13

@铁石心肠

我会一直带着EAV和MVC来这里.

@Bill Karvin

以下是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, e.g.
Run Code Online (Sandbox Code Playgroud)

查找表.

你在这里提到的所有事情:

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

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

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

在传统的表格布局中获取结果既复杂又昂贵,因为要从多个行获取属性,您需要为每个属性执行JOIN.

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

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

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

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


JD *_*cks 5

如果我使用Class Table Inheritance含义:

一个产品表,存储所有产品类型共有的属性.然后是每个产品类型一个表,存储特定于该产品类型的属性. - 比尔卡文

我最喜欢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类与数据库交互来提取产品信息; 那么如果代码中的任何更改现在需要重构,那么它们应该仅适用于该类.