【问题标题】:What is the best schema design for child collection with a "primary" entity具有“主要”实体的子集合的最佳模式设计是什么
【发布时间】:2010-05-18 13:02:20
【问题描述】:

以下是场景:您有一个 Persons 表,它与一个 Addresses 表具有一对多关系,其中 Address 行之一是“主要”地址。

在标准化架构中是否更好

  • 使用 Persons.PrimaryAddressID 访问人员的“主要”地址

  • 使用 Addresses.IsPrimary 位列通过 Addresses.PersonID 引用人员的“主要”地址

  • 其他

为什么?

【问题讨论】:

    标签: database-design database-schema


    【解决方案1】:

    这取决于人与地址的关系是一对零加还是一对一加。

    如果一个人需要有一个主要地址,我会把它放在Persons 表本身中(因为它是一个必需的属性)。


    另一方面,如果一个人可以在没有地址的情况下存在于您的架构中,我会将Addresses 表中的所有地址保持相同,并使用Persons 表的属性来选择主要的(NULL或指向相关Addresses 行的指针)。

    如果您将地址的素数存储在 Addresses 表中,当 Bob Smith 的两个地址都声称是主要地址时,您会怎么做?您可以使用触发器来阻止这种情况,但正确设计架构会更有效。

    而且,如果两个室友共享同一个地址,但一个人一直住在那里,而另一个人大部分时间都和他的女朋友同居,那会发生什么?如果素数在 Addresses 表中,您将无法在人员之间共享地址行。


    我想要表达的是,您需要将属性分配给正确的对象。一个人的主要地址属于一个人,而不是一个地址。

    为了最大限度地提高效率和灵活性,我将采用以下架构:

    Persons:
        Id                 primary key
        PrimaryAddressId
        OtherStuff
    Addresses:
        Id                 primary key
        OtherStuff
    PersonAddresses:
        Id                 primary key
        PersonId           foreign key on Persons(Id)
        AddressId          foreign key on Addresses(Id)
    

    你有一个小的数据完整性问题,Persons.PrimaryAddressId 可能是一个悬挂指针。您不能将其作为主键之一的外键,因为您希望它允许 NULL。这意味着您必须考虑到它可能指向不存在的Addresses.Id

    我会简单地将其修复为 Addresses 上的删除前触发器,以便更新相关的 Persons 行(将 PrimaryAddressid 设置为 NULL)。

    或者你可能会很棘手,在Addresses 表中有一个“未知”地址,这样Persons 中的每一行都至少有一个地址(那些主地址未知的人会自动将他们的PrimaryAddressid 设置为“未知”地址行。

    然后你可以使它成为一个适当的约束关系并稍微简化你的 SQL。在现实世界中,实用主义往往胜过教条主义:-)

    【讨论】:

    • 如果 Persons->Addresses 关系被限制为一对多,而不是允许的人对多,你还会使用这种设计吗?在这种情况下,可能偶尔会出现重复的地址,但在您的室友场景中,例如,如果一个室友搬出,您不想更改两个室友的地址。
    • 如果真的是一对多,我会重新考虑。但我不认为这种特殊情况值得这样做。使这种一对多重复数据库中的数据是不必要的。在搬家的情况下,您不会为留下来的科学怪人更新地址行,您只需将计算机书呆子主目录更改为指向一个新的地址记录,如果他的女朋友在校园内就已经存在,或者只是添加一个如果她去路上的啦啦队学校,那就是新的:-)
    • 从技术上讲,表中根本不应该有重复的行。地址是一个对象,该对象的所有属性都应该在它的单行中。当史密斯街 7 号有两排并且他们对地址有不同的想法时会发生什么? DBA 周游世界,试图解决此类问题。不要让我过来 :-)
    • 当前原型实际上执行了您上面提到的操作,只要在没有 PrimaryAddressID 的情况下保存 Person 时,就会插入一个新的“未知”地址行。重新重复地址:我明白你在说什么,但是重复地址的数量会相对较少,并且似乎实施可能存在错误的业务逻辑来处理重复和不重复地址的各种情况可能不如只是有一些重复。不?你现在可以用尺子敲打我的指关节了:)
    【解决方案2】:

    我会选择“使用 Persons.PrimaryAddressID 访问人员的“主要”地址”。 主要地址仅在人员链接到地址时才有意义。所以它应该属于Person。考虑以下第二种方法失败的情况。

    a) Address 与另一个实体一起使用,但没有引用 Addresses.IsPrimary 没有意义的人。

    b) 两个人使用相同的地址,其中第一个用作主要地址,而第二个不是。

    【讨论】:

    • 关于“主要”如何仅在链接存在时才有意义的要点。
    【解决方案3】:

    如果您希望一个人最多有一个主要地址,Persons.PrimaryAddressID 显然更简单——实际上,它是由架构强制执行的。确保每个人正好有一个 主地址也很容易(只需使该列不为空),如果需要,甚至可以说没有两个人可以共享一个主地址(只需将该列设为是独一无二的)。

    当然,正是因为这种方法擅长执行这些简单的约束,所以当你想要这些约束时,它是不好的——例如,如果你想让一个人能够如果有多个“主要”地址,则相关方法将不起作用。

    顺便说一句,我不会认为一个人/多个地址的关系特别好除非你想强制执行这样一个事实,即没有两个人可以共享同一个地址:一般来说,在一种正常化的情绪,我宁愿有一张人的桌子,一张地址,一张用于关系(在大多数情况下,这自然是多对多的,因为很多人都可以,而且在现实生活中,分享同一个地址)。

    如果你选择走这条路,那么,特别是如果你需要高度的灵活性(多个主地址 &c),让关系表带有“primality”布尔值将是一个有吸引力的选择(它仍然不会太难强制执行上述一些约束,但其他约束,例如“地址属于至少一个人”或反之亦然,可能很难简单地表达)。

    要记住的教训:准确地表达您的架构需要简单表达的约束,并且用于该目的的正确架构通常会非常清晰地出现。如果感兴趣的约束是一个谜,那么“什么是正确的模式”这个问题的答案也将是一个谜;-)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-08
      • 2011-02-25
      相关资源
      最近更新 更多