【问题标题】:Parent child design to easily identify child type父子设计,轻松识别子类型
【发布时间】:2017-02-02 23:37:21
【问题描述】:

在我们的数据库设计中,我们有几个表来描述不同的对象,但它们具有相同的基本类型。由于描述实际表和每列正在做什么需要很长时间,我将尝试通过使用基于作业数据库的类似结构化示例来简化它。

假设我们有以下表格:

这些表彼此之间没有连接,但共享相同的列。所以第一步就是统一相同的列,引入唯一的personId:

现在我们有了 person 中的“标题”列,然后使用 personId PK 作为 FK,使用 1 对 1 关系将它们链接到更具体的作业表。在我们的用例中,一个人只能拥有一份工作,因此 personId 在 Taxi driver、Programmer 和 Construction worker 表中也是唯一的。

虽然这种结构有效,但我们现在有这样一个用例,在我们的应用程序中,我们获取 personId 并希望获取相应工作表的数据。这给我们带来了一个问题,即我们无法立即知道拥有此 personId 的人在做什么。

我们想出了几个解决这个问题的方法:

在后台处理

这意味着保持架构不变并在后端代码中查找正确的表。这可能意味着查看存在的每个表和/或构建一个半复杂的连接选择,我们必须在其中筛选所有列以找到已填充的列。

总而言之:可能但意味着很多不必要的选择。我们还希望在实际数据库中保留这种面向数据库的逻辑。

使用类型字段

这意味着在 Person 表中添加一个字段列,例如用数字填充以确定正确的子表,例如:

因此,如果是出租车司机,则可以在 Type 中添加 0,如果是程序员,则可以添加 1,依此类推...

虽然这大大减少了后端逻辑的数量,但我们必须确保我们在 Type 字段中使用的数字在后端是已知的并且永远不会改变。

为每个表使用单独的 ID

这意味着每个工作在 Person 中都有自己的 ID(必须可以为空),例如:

现在,由于其他人的 ID 为空,因此很容易找出每个人从事的工作。

所以我的问题是:这些设计中哪一种是最佳实践?我在这里错过了一个明显的解决方案吗?

【问题讨论】:

  • 我想我会选择类型字段选项。但是,您为什么要放弃您开始使用的简单 3 表模型?
  • 鉴于您已有的内容,添加一个 PersonTypeId,并将其作为 PersonTypes 表的 FK。第一个解决方案需要大量开销来记住您已经知道的东西,最后一个解决方案很快变得非常复杂,并且还引入了一个人与两个或多个工作类型相关联的可能性(这可能是可以的),但令人困惑。
  • @BobC 由于名称和年龄列在所有表中都是相同的,这仅意味着在进行大量维护时,例如,所有工作类型的名称列需要稍长一些。此外,我们希望有一个唯一的 ID 来识别一个人。在多个展开的桌子上设置它会很麻烦。此外,它不会真正帮助我们解决问题,因为我们仍然会遇到问题,试图找出 ID 为“3”或名称为“Dave”的人从事什么工作。
  • 我通常选择#2,即有一个类型字段,但使用枚举而不是 ID 字段,例如'TAXI-DRIVER'、'PROGRAMMER'、'CONSTRUCTION-WORKER' 带有检查约束。

标签: database oracle database-design


【解决方案1】:

Bill Karwin 对与此类似的问题做了很好的解释。 https://stackoverflow.com/a/695860/7451039

【讨论】:

  • 您应该在答案中给出一些解释,至少将链接中的一些相关信息复制到您的答案中,或者在链接的答案中解释解决方案,而不是给出(几乎)仅链接的答案你自己的话。
【解决方案2】:

我们现在决定采用第二个选项,因为正如其他评论者和发帖者所描述的那样,它的缺点似乎最少。由于没有将第二个选项描述为解决方案的实际答案,我将尝试总结我们的推理:

反对选项 1:

没有办法通过查看父表来区分类型。因此,后端必须包含所有逻辑,其中包括扫描所有表以查找包含 id 的表。虽然您可以将大部分逻辑压缩到一个大的 Join 选择中,但与其他选项相比,它仍然是更多的逻辑。

反对选项 3:

正如@yuri-g 所说,这在技术上是不可能的,因为单独的 ID 无法设置为主键。它们必须是可空的,因此不能被索引,本质上使父表无用,原因之一是在表中具有唯一的 personID。

针对包含所有列的单个表:

对于我在问题中描述的较小的用例,这可能是可行的,但我们正在讨论一堆表,每个表大约有 2-6 列。这会使这个选项很快变成一个列混乱。

反对带有键值表的扁平化设计:

我们的属性具有完全不同的数据类型、不同的约束和外键关系。在这个设计中,所有这些都是不可能/困难的。

针对包含子特定属性的自定义数据库对象:

虽然@Matthew McPeak 建议的这个选项对于很多人来说可能是一个可行的选择,但我们的数据库设计从未真正使用过对象,因此将它们引入组合可能会导致混乱,而不是帮助我们。

赞成第二种选择:

这个选项在我们面向表的数据库结构中很容易使用,可以很容易地区分正确的子表,并且不需要大量的修改来引入。尤其是因为我们已经有了类似于 Type 表的东西,我们可以轻松地将其用于此目的。

【讨论】:

    【解决方案3】:

    正如您所描述的,第三个选项是不可能的:没有任何 RDBMS(至少,我个人知道)允许您在 PK 中使用 NULL(甚至是复合)。

    第二个是现实的。

    是的,首先需要最多 N 个查询来轮询亲属以确定实际类型(其中 N 是类型的数量)。 尽管在第二种情况下您也不会使用一个查询来逃避:总会有两个,因为除非您知道自己应该加入什么,否则您无法加入。

    所以基本上你的设计存在缺陷,你应该在那里考虑其他选择。 就像,非规范化:无论如何将非共享属性行到父表中,然后字段变为非对应类型的空值。 或者通过主键关联的灵活、扁平的属性值对列表(是的,模式实施是一种权衡)。

    或者切换到面向列的数据库:就是这样。

    【讨论】:

    • 我们现在决定采用第二种选择,因为正如您所说,它似乎是最现实的选择。您使用具有许多列的单个表描述的方法将非常乏味,因为我们的实际案例总体上更接近第 10-20 列。您提到的其他平面设计也会适得其反,因为我们将在表值上使用约束和外键关系。
    • 我没有对评论投反对票。我不知道是谁干的。
    猜你喜欢
    • 1970-01-01
    • 2020-08-04
    • 1970-01-01
    • 1970-01-01
    • 2017-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    相关资源
    最近更新 更多