同一数据库表中的许多高度相似的对象

时间:2012-03-09 08:31:32

标签: mysql sql database database-design

您好,stackoverflow社区!

我正在开发一个相当大的数据库驱动的Web应用程序。随着更多组件的添加,底层数据库的复杂性越来越高,但到目前为止,我已经完全正确地规范化数据了。

但是,这个最终组件意味着一个可以容纳产品的表。 每个产品都有一个类别,根据类别,有不同的字段。 为每个产品类别制作一个表似乎不对,因为目前有五种类型,它们仍然有很多共同的领域。 (但是以奇怪的方式 - 描述和价格等一些通用字段对于所有5个类别都是通用的,但是一些属性在1和2之间共享,其他属性在3,4,5之间共享等等。)

出于明显的性能原因,我正试图避开EAV模型。

问题在于,根据用户想要输入数据库的产品类型,有一些(但不是完全)不同的字段结构 - 所有这些都有名称和一般描述,但其他属性如“area”涵盖“只适用于某些类别,如种子和杀虫剂,但不适用于燃料,这将具有柴油/汽油布尔值以及一系列其他与燃料相关的属性。

我应该只提取表中的核心功能,并为每个类别类型再创建五个功能吗?那将来有点难以扩展。

我目前的想法是让产品表包含所有可能类别中的所有字段,然后再使用另一个表来描述产品表中哪个类别包含哪些字段。

product:        id | type | name | description | price | composition | area covered | etc.

fields:         id | name (contains a list of the fields in the above table)

product-fields: id | product_type | field_id (links a bunch of fields to the product table based on the product type)

我认为这不会太慢,很容易搜索(不需要实际加入其他表,只需根据一些输入在主产品表上执行搜索),这样可以方便表单生成和数据仅使用一个轻量级附加查询/连接进行验证。 (从数据库中获取产品并加入字符串中实际使用的字段的连接列表 - 将其拆分并根据其包含的内容显示正确的表单字段,即与该产品实际关联的字段。

谢谢你的麻烦! 安德烈·巴尔桑

3 个答案:

答案 0 :(得分:2)

当您知道密钥时,EAV实际上可以非常擅长存储数据并再次获取数据包。它还具有在不更改架构的情况下添加字段的能力。但是当你需要相等的WHERE field1 = x and field2 = y时,它很糟糕。

因此,虽然我同意数据行为很重要(有多少产品共享相同的字段等),但该数据的使用很重要。

  • 哪些字段需要搜索,哪些字段始终只是数据存储等

在大多数情况下,我建议将所有需要搜索的字段保存在同一个表中。

在实践中,这通常会导致单个表解决方案。

  • 新字段需要架构更改,新索引等
  • 数据稀疏的可能性,使用的空间比“必需”更多
  • 允许简单查询,简单索引以及通常最快的查询
  • 通常,虽然并非总是如此,但空间开销是微不足道的

在稀疏数据开销达到临界点的情况下,我会转向按其包含的字段分组的其他表。更具体地说,我 按产品创建表格。这是双重假设,大多数/所有字段将至少在某些产品中共享,并且这些字段需要搜索。

这使得架构更像......

Main_table ( PK, Product_Type, Field1, Field2, Field3 )
Geo_table  ( PK, county, longitute, latitude )
Value      ( PK, cost, sale_price, tax )
etc

您可能还有一个元数据表,描述哪些产品类型具有哪些字段等

这个模式允许的是一组密度更大的表,可以很容易地编制索引并快速搜索,同时通过对相关字段进行分组来最小化表混乱和连接。


最后,没有真正的 回答 ,这都是一种平衡行为。我的一般经验法则是留在一张桌子上,直到我真正有一个真实而紧迫的理由,而不仅仅是理论上的。

答案 1 :(得分:1)

根据我的经验,除非您正在编写一个可以呈现完整描述字段的完整框架(我们正在讨论描述每个字段的大量元数据),否则不值得将字段定义与主要对象分开。现代框架(如Grails)允许虚拟零痛苦,为域/模型类和表添加新列。

如果所有对象类型之间的公共字段重叠大约为80%,我会将它们全部放在1个表中,并使用Table per Hierarchy继承模型,其中descriminator字段可帮助您区分对象类型。另一方面,如果您有20%的公共字段重叠,那么请使用Table per Class继承模型,其中基类和包含公共字段的表。其他联合桌子悬挂在底座上。

答案 2 :(得分:1)

  

我应该只提取表中的核心功能,并为每个类别类型再创建五个功能吗?那将来有点难以扩展。

这称为 SuperType - SubType 关系。如果您的大多数查询都是以下两种类型之一,它的效果非常好:

  1. 如果您将主要查询SupetType表,并且不经常深入查看SubType表。
  2. 如果您在过滤到特定子类型后将查询数据库。