【问题标题】:One table per every similar object?每个类似的对象一张桌子?
【发布时间】:2010-11-16 14:46:28
【问题描述】:

我为绘图店编写了一个应用程序。我的系统中有这些类:shop、cart place、rack 和 bakery。

它们具有以下属性:

店铺:X、Y、名称、宽度、高度、类型、地址

购物车位置:X、Y、名称、宽度、长度、类型、容量

机架:X、Y、名称、宽度、长度、类型、高度、平衡限制

面包店:X、Y、名称、宽度、长度、类型、营业时间

现在我想在我的数据库中表示这些类。但是你可以看到上面的所有类都有相同的东西,比如:

X、Y、宽度、高度、名称和类型。让它们与众不同的是:

店铺:地址

购物车位置:容量

机架:balance_limit

面包店:营业时间

我知道,未来所有这些类型的对象都将拥有自己的新属性,并且它们将获得所有这些对象同时拥有的新属性。

而且我知道会有上面没有提到的新类型的对象,它们将具有与商店、购物车位置、货架和面包店相同的一些属性。

我想创建允许我添加新属性和新对象的数据库结构。并添加将同时添加到每个类的新属性。此外,我希望系统设计清晰,并允许我对其进行简单的数据库查询。

所以我的问题是:

我应该为每种类型的对象(商店、购物车位置、货架、面包店)创建一个数据库表,因为这样会更清晰,还是应该将它们全部组合到一个表中,因为它们具有相似的属性列表?

我希望您能告诉我为什么一种解决方案会比另一种更好。我希望在这里得到一些实用的建议,而不仅仅是“你应该这样做,因为这是正确的方式,公理”。

【问题讨论】:

    标签: database database-design data-structures normalization


    【解决方案1】:

    这不是一个简单的问题...SQL 数据库不擅长对类层次结构建模。

    你需要一个好的 ORM。

    我把一个类层次结构放在一个表中,这样做是:

    首先我确保它是相关的:例如,将网络 CMS 的节点、文章等放在同一个表中是有意义的,因为这些都是同一事物的变体。

    这个想法是您需要创建用于搜索、索引和进行 SQL 查询的数据库列,但您不需要将所有信息存储在数据库列中。您可以将其余部分存储在 BLOB 列中的序列化对象中。

    在表中,有 - 当然有一列表明该行是哪个类的实例 - 一些所有类共有的“核心”列,基本上是基类字段。 - 仅由某些子类使用但我需要搜索的其他列,因此需要对它们进行索引 - 一个包含对象中所有其他数据的 BLOB。

    基本上当我在数据库中存储一个对象时,会根据其类填充相关列,并将其余数据(甚至整个对象)推入 BLOB。

    这样做的好处是,如果你添加一个不需要搜索或索引,只存储的成员值,你不需要把它放在数据库列中,所以你不需要对数据库:它将存储在序列化的 BLOB 中。唯一要做的就是在你的反序列化代码中为这个成员添加一个默认值,这样已经在数据库中并且没有这个成员的这个类的对象将有一个像样的默认值。

    您还可以根据需要对对象格式进行版本控制,它会变得更加复杂。

    但是这个方案有一些缺点:

    约束很难应用: - 您只能将约束应用于具有列的字段。 - 由于某些列仅出现在某些类中,因此数据库需要了解您的类层次结构。

    例如,您可能希望将地址放在单独的表中,并添加相关字段(邮政编码、国家/地区、街道、号码等):将所有这些都放在主表中会添加太多列。此外,在某些时候,您会想要添加一些客户或其他位于不同表中并且也有地址的东西,因此最好将地址放在单独的表中并引用它们。

    对于个人或公司等也是如此。

    现在商店有地址,但购物车没有,我想,所以你必须在数据库 DDL 中表示,如果表中的一行是“shop”类型但不是“类型”,则表中的一行必须引用地址购物车”。

    它可能会有点毛。

    另外,例如,如果您有 10 家商店和 100.000 辆购物车,出于性能考虑,拆分桌子可能会很有趣,这样您就可以得到一张漂亮的快速小桌子和一张大桌子。


    现在还有其他解决方案:

    例如,您可以将所有代码和基成员放在基类中,但将 tableName 设置为在派生类中更改的类属性。这样,只需更改表名,所有代码都适用于不同的表,而您不必重写任何代码。

    然后每个班级有 1 张桌子。

    如果您的类层次结构变得更复杂,您当然可以在每个表上应用上述方法。


    两者如何选择?

    基本上,如果您制作一个网络 CMS 并将其存储在一个表中,则从 Node 派生的类的对象如下: - 文章 - 带有图例的图像 - 画廊 - 等等

    所有这些对象基本上都是相同的东西。 它们都有一个 Title、一个 TextContent 字段、属于一个 ParentNode 等

    如果您在 TextContent 中对“foo”进行关键字搜索,如果所有对象都在同一个表中,则会容易得多。

    如果您想列出 ParentNode 的所有子节点以将它们显示在网页上,如果所有内容都在 1 个表中,也会容易得多。

    所以在这种情况下,第一种方法确实有好处。

    现在,在您的情况下,对象并不那么相似。

    就我个人而言,我什至不会给他们相同的基类。 我会创建一个名为“ThingWithCoordinates”的 Mixin(可能更短一些)并将其添加到类中。

    现在,也许面包店离商店足够近,它可以从商店继承,但推车和货架可能不是。

    在你的情况下,我肯定会使用几张桌子。而在每张表中,如果需要存储多个类,我会使用第一种方法。

    最重要的是,您的类层次结构(以及表格)必须基于相关的东西(汽车经销商和面包店是商店),而不是碰巧存在于实际上没有其他共同点的对象之间存在的共同特征(如购物车和店铺)。为此,有一些 mixin 可以共享通用代码,但没有基类。

    【讨论】:

      【解决方案2】:

      我的建议:

      1. 正确设计您的domain model,而不考虑数据库问题。共享属性的实体(例如名称)并不意味着它们有任何关联。虽然他们很可能......
      2. 将此设计映射到数据库结构,选择众所周知的Object-Relational Structural Patterns(参见Database Design)。
      3. 使用适当的 ORM 解决方案(最好是允许之后修改底层数据库结构的解决方案)开发您的产品。
      4. 如果您遇到性能问题,请考虑使用(de)normalizing 您的数据库来解决问题。

      【讨论】:

        【解决方案3】:

        是的,您应该为每个对象使用一个表,因为它们是它们自己的实体。 如果将这些表映射到对象,则无需连接多个表,从而提高效率。

        然后每个对象在开发和复杂性方面都是孤立的。

        【讨论】:

          【解决方案4】:

          您从“共享”常见项目的表格中获得什么好处?

          如果没有,则不要这样做 - 只需将它们放在不同的表中(尤其是如果它们将来会进一步分歧)。

          我猜你没有使用 ORM?

          【讨论】:

            【解决方案5】:

            在网上搜索“泛化专业化关系建模”。

            当这种模式出现时,您将找到几篇关于如何设计 SQL 数据库的好文章。最好的文章遵循您提供指导而不是制定规范规则的标准。

            【讨论】:

              【解决方案6】:

              如果共性类似于 shop_size,那么我建议为此创建一个单独的表。

              原因是通过规范化您可以获得其他信息,例如,它可以很容易地显示宽度和长度,因为可能有许多商店具有相同的尺寸。

              您也可以稍后查看此表中的数据以获取其他信息。

              主要是,您可以获得灵活性,IMO。

              【讨论】:

                猜你喜欢
                • 2010-11-26
                • 2013-12-30
                • 2012-05-23
                • 1970-01-01
                • 1970-01-01
                • 2017-02-07
                • 2011-11-17
                • 2011-10-09
                • 2020-07-29
                相关资源
                最近更新 更多