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

EdH*_*EdH 18 sql database sql-server database-design entity-framework

我们正在开始一个新项目,我们需要在数据库中存储产品和许多产品属性.技术堆栈是MS SQL 2008和Entity Framework 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
...
Run Code Online (Sandbox Code Playgroud)

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

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

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

谢谢!-ed

Rem*_*anu 17

您即将重新发明可怕的EAV模型,Entity-Attribute-Value.这是出于现实生活中的问题而臭名昭着,出于各种原因,戴夫的回答涵盖了许多问题.

幸运的是,SQL客户咨询团队(SQLCAT)有一个关于该主题的白皮书,即 性能和可伸缩性的语义数据建模的最佳实践.我强烈推荐这篇论文.不幸的是,它没有提供灵丹妙药,一个千篇一律的解决方案,因为问题没有解决方案.相反,您将学习如何在固定的可查询架构和灵活的EAV结构之间找到平衡,这种平衡适用于您的特定情况:

语义数据模型可能非常复杂,并且在语义数据库通常可用之前,挑战仍然是在每个应用程序的纯对象模型和纯关系模型之间找到最佳平衡.成功的关键是理解问题,对这些问题进行必要的缓解,然后进行测试,测试和测试.如果您要找到最佳设计,可伸缩性测试是一个关键的成功因素.


Dav*_*kle 14

由于以下几个原因,这将成为问题:

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

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

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

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

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

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

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

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

IMO这是一个设计反模式.这个想法的警笛歌曲吸引了许多开发人员进入一个无法维护的应用程序的岩石.


小智 5

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

我已经看到了平衡 EAV 与属性建模方法。嗯 - 它仍然是 EAV。“EAV 就像毒品”是千真万确的。那么,再仔细考虑一下怎么样——让我们真正积极一点:我仍然喜欢超类型方法,其中许多表使用来自密钥生成器的相同主键。让我们重用这个吧。那么,为每组属性创建一个新表怎么样?所有属性都具有来自同一密钥生成器的主表?例如。您将有一个包含字段“颜色,管道”的表,另一个表“配件尺寸,管道”,依此类推。无论如何,“属性的波动性”要求需要仔细(自动)维护的数据字典。

这种方法是完全标准化的并且可以完全自动化。您可以支持检查特定属性集是否已通过散列属性名称簇具体化为表,例如。crc32(lower('color~fittingsize~pipe')) 其中属性名称需要按字母顺序排序。当然,这需要数据字典中有哈希值。基于数据字典,可以搜索每个对象(使用“UNION”),特别是当数据字典本身是一个表时。将数据字典作为表还允许您使用其主(代理)键作为唯一表名的基础,最终得到诸如“attributes1”、“attributes2”之类的表......现在大多数数据库都支持数十亿个表 - 所以我们在这方面也算是节省了。您甚至可以拥有一个包含非常常见属性的产品目录,该目录引用扩展属性表。

一个未解决的问题是 1:n 数据集。恐怕您需要将它们分类在单独的表中。然而,这在很大程度上取决于您的数据呈现和查询策略。它们是否应该始终以逗号分隔的字符串形式附加到产品上,或者您是否想要例如。可以查询某个认证的所有产品吗?

在您使用这种方法之前,请考虑这一点:它仅适用于属性(数量和质量)波动性非常高的用例。此外,它也是预设的,您无法知道创建解决方案时的大多数属性。因此,不要在可以预先对属性进行建模的环境中讨论此问题,这将使您能够更好地平衡权衡。