在SQL Server中存储(产品)属性的最佳模式

时间:2010-05-26 00:29:02

标签: sql sql-server database entity-framework database-design

我们正在开始一个新项目,我们需要在数据库中存储产品和许多产品属性。技术堆栈是MS SQL 2008和实体框架4.0 / LINQ,用于数据访问。

产品(和产品表)非常简单(SKU,制造商,价格等)。但是,每种产品也存在许多属性(想想工业小部件)。这些可能从颜色到认证到管道尺寸。每个产品可能具有不同的属性,有些可能具有相同属性的倍数(例如:认证)。

目前的建议是,我们基本上会有一个名称/值对表,其中FK返回每行的产品ID。

属性表的示例可能如下所示:

ProdID     AttributeName     AttributeValue
123        Color             Blue
123        FittingSize       1.25
123        Certification     AS1111
123        Certification     EE2212
123        Certification     FM.3
456        Pipe              11
678        Color             Red
999        Certification     AE1111
...

注意:属性名称可能来自查找表或枚举。

所以这里的主要问题是:这是做这样的事情的最佳模式吗?表现如何?查询将基于产品和属性表的JOIN,并且通常需要许多WHERE来过滤特定属性 - 最常见的搜索将是基于一组已知/期望的属性来查找产品。

如果有人对此类数据有任何建议或更好的模式,请告知我们。

谢谢! -Ed

5 个答案:

答案 0 :(得分:16)

您即将重新发明可怕的EAV模型,Entity-Attribute-Value。由于各种原因,这在现实生活中存在问题是很臭名昭着的,Dave的回答涵盖了许多问题。

幸运的是,SQL客户咨询团队(SQLCAT)有一个关于该主题的白皮书, Best Practices for Semantic Data Modeling for Performance and Scalability。我强烈推荐这篇论文。不幸的是,它没有提供灵丹妙药,一个千篇一律的解决方案,因为问题没有解决方案。相反,您将学习如何在固定的可查询架构和灵活的EAV结构之间找到平衡,这种平衡适用于您的特定情况:

  

语义数据模型可以非常   复杂,直到语义数据库   通常可用,挑战   仍然找到最佳平衡   纯对象模型和   每个人的纯关系模型   应用。成功的关键是   了解问题,制作   必要的缓解措施   问题,然后测试,测试和测试。   可伸缩性测试至关重要   成功因素,如果你要去   找到最佳设计。

答案 1 :(得分:13)

由于以下几个原因,这会有问题:

  • 您的实体查询将更难写。在演示时将这些查询的结果转换为类似于ViewModel的内容将会很痛苦,因为它将涉及每个产品的支点。

  • 在阅读某些类型的数据时,了解您的数据类型将会很困难。你打算把它存储为字符串吗?例如,DateTimes保存的数据多于默认的.ToString()实现写入字符串。如果您尝试存储浮点值,也会遇到问题。

  • 您的对象的数据完整性存在风险。在这个“存储数据”中放置属性应该只是主要产品表的属性是一种诱惑。也许设计从一开始就是半合理的,但我向你保证,经过一段时间后,人们才会开始将物品扔进包里。然后很难通过如此松散定义的结构来保持对象的完整性。

  • 您的索引很可能不是最理想的。再想想应该在您的产品表上的属性。现在,您将不得不在一个列上进行索引,而是强制在“类型”表上创建一个可能非常大的复合索引。

  • 由于您显然计划丢弃正确的数据类型并使用字符串,因此数值数据范围查询的性能可能会很差。

  • 您的表格会变大,减慢备份和查询速度。而不是一个4字节的整数,你将不得不为任何大小的整数存储更多。

最好使用“IS-A”关系以更“传统”的方式规范化表格。例如,您可能有Pipes,它是一种Product,但有更多属性。您可能有Stoves,它是一种产品,但仍然有更多属性。

如果您确实拥有通用数据库以及不受数据完整性规则约束的各种其他属性,那么您可能需要考虑将数据存储在XML列中。除非我对您的业务了解更多,否则很难告诉您正确的设计选择。

IMO这是一个设计反模式。这个想法的警笛歌曲吸引了许多开发人员陷入难以维护的应用之中。

答案 2 :(得分:4)

我知道这是一个旧的 - 但可能还有其他读者......

我已经看到了平衡EAV属性建模方法。嗯 - 它仍然是EAV。 “EAV就像毒品一样”非常真实。那么再一次思考它又是什么呢?让我们真的好斗: 我仍然喜欢超类型apporach,其中许多表使用来自密钥生成器的相同主键。让我们重用这个。那么为每组属性创建一个新表怎么样 - 所有属性都来自同一个密钥生成器?例如。你会有一个表格,其中包含“颜色,管道”字段,另一个表格“配件,管道”等。无论如何,要求“属性的波动性”都会为精心(自动)维护的数据字典而尖叫。

此方法已完全标准化,可以完全自动化。如果特定属性集已经通过散列属性名称簇实现为表,则可以支持检查,例如。 crc32(lower('color~welitsize~pipe'))其中属性名称需要按字母顺序排序。当然,这需要在数据字典中使用哈希。基于数据字典,可以搜索每个对象(使用“UNION”),尤其是在数据字典本身是表的情况下。将数据字典作为表也允许您使用其主要(代理)键作为唯一表名的基础,最终得到像'attributes1','attributes2'这样的表,...现在大多数数据库支持数十亿个表 - 所以我们在这方面也有点保存。您甚至可以使用具有非常常见属性的产品catalouge来引用扩展属性表。

一个未解决的问题是1:n数据集。我担心你需要在单独的表中对它们进行排序。但是,这在很大程度上取决于您的数据表示和查询策略。它们是否应始终以附带在产品上的逗号分隔字符串表示,或者您是否希望例如。能够查询某个认证的所有产品吗?

在你激发这种方法之前,请考虑以下事项:它适用于只有数量和质量非常高的属性波动性的用例。此外,它已预设,您无法在创建解决方案时了解大多数属性。所以不要在可以预先建模属性的环境中讨论这个问题,这样可以更好地平衡权衡。

答案 3 :(得分:2)

简而言之,你无法走一条路。如果您使用类似于您的示例的EAV,您将遇到无数问题,例如其他海报所概述的问题,其中最重要的是性能和数据完整性。让我重申一下,当您进行报告和分析时,使用EAV作为解决方案的核心将失败。但是,正如您所说,您可能有数百个定期更改的属性。

解决方案,IMO,是一个混合体。对于公共属性,请使用列/标准架构。对于其他任意属性,请使用EAV。但是,使用EAV数据的规则是,在任何情况下,您都不能编写包含对属性进行排序或过滤的查询。即,你永远不能写Where AttributeName = 'Foo'。模式的EAV部分代表一袋数据,仅用于跟踪目的。事实上,我已经看到许多人通过使用Xml为EAV部分实现此解决方案。当某人想要在报告的特定位置搜索,过滤,排序或放置EAV值时,该属性必须提升到products表中的顶级列。

这种混合方法的关键是纪律。在报表的某个位置添加过滤器,排序或将属性放在特定位置似乎很简单,尤其是当您从管理层获得压力时。你必须抵制这种诱惑。一旦你走上了黑暗的道路......如果你不认为你可以在你的开发团队中维持这种程度的纪律,那么我就不会使用EAV。正如我之前提到的,EAV就像药物一样:少量使用并在适当的环境下使用它们可能是有益的。太多会杀了你。

答案 4 :(得分:1)

不是拥有名称 - 值表,而是创建包含所有常用属性的常用Product表结构,并为因产品而异的属性添加XML列。

之前我使用过这种结构,效果很好。

正如@Dave Markle所提到的,名称价值方法可能导致一个痛苦的世界。