【问题标题】:Many highly similar objects in the same database table同一个数据库表中有许多高度相似的对象
【发布时间】:2012-03-09 08:31:32
【问题描述】:

你好,stackoverflow 社区!

我正在开发一个相当大的数据库驱动的 Web 应用程序。随着更多组件的添加,底层数据库变得越来越复杂,但到目前为止,我完全没有遇到任何问题,可以很好地规范化数据。

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

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

问题是,根据用户想要输入数据库的产品类型,有一些(但不完全)不同的字段结构 - 它们都有名称和一般描述,但其他属性,例如“区域覆盖”只能应用于某些类别,例如种子和杀虫剂,但不能应用于具有柴油/汽油布尔值和许多其他燃料相关属性的燃料。

我应该只提取表格中的核心特征,并为每个类别类型再制作五个吗?这在未来会有点难以扩展。

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

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)

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

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

【问题讨论】:

    标签: mysql sql database database-design


    【解决方案1】:

    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
    

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

    此架构允许的是一组更密集的表,可以轻松地对其进行索引和快速搜索,同时通过对相关字段进行分组来最大程度地减少表混乱和连接。


    最后,没有真正的答案,这都是一种平衡行为。我的一般经验法则是在一张桌子上呆着,直到我真正有理由不这样做,而不仅仅是理论上的理由。

    【讨论】:

    • 由于允许用户根据几乎任何列进行搜索,我想主表+元数据表将是最好的方法。我不认为会有太多稀疏填充的条目(总共大约 20 列,最坏的情况是只使用 11/20 列,最好的情况是 17/20)。
    • 我采用了单表+元表的方法,到目前为止效果很好!从长远来看,我会看看它是如何运作的,但鉴于目前的情况,我没有看到这种方法可能在压力下崩溃的任何特定地方。谢谢!
    【解决方案2】:

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

    如果您的公共字段在所有对象类型之间的重叠率约为 80%,我会将它们全部放在 1 个表中,并使用按层次结构继承模型的表,其中标识符字段可帮助您区分对象类型。另一方面,如果您有 20% 的公共字段重叠,则使用具有基类和包含公共字段的表的每个类继承模型的表。和其他联合表挂在底座上。

    【讨论】:

    • 我正在使用 CodeIgniter,只要脚本知道要为哪些字段呈现条目,我就不会在表单呈现方面遇到太多问题。
    【解决方案3】:

    我应该只提取表格中的核心特征,然后为每个类别类型再制作五个吗?这在未来会有点难以扩展。

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

    1. 如果您将主要查询 SupetType 表,而很少深入到 SubType 表。
    2. 如果您将在过滤到特定子类型后查询数据库。

    【讨论】:

    • 遗憾的是,搜索有时会深入到每个可能的类别字段。此外,还需要为每个可能的产品类型添加一个新表,这听起来也不太好。
    猜你喜欢
    • 1970-01-01
    • 2018-06-25
    • 1970-01-01
    • 1970-01-01
    • 2015-11-23
    • 1970-01-01
    • 2014-03-23
    • 2016-05-13
    • 1970-01-01
    相关资源
    最近更新 更多