我记得在播客014中听到Joel Spolsky提到他几乎从未使用过外键(如果我没记错的话)。然而,对我来说,它们对于避免数据库中的重复和后续数据完整性问题非常重要。
人们是否有一些可靠的理由(以避免与Stack Overflow原则一致的讨论)?
编辑:“我还没有创建外键的理由,所以这可能是我真正建立一个外键的第一个理由。”
我记得在播客014中听到Joel Spolsky提到他几乎从未使用过外键(如果我没记错的话)。然而,对我来说,它们对于避免数据库中的重复和后续数据完整性问题非常重要。
人们是否有一些可靠的理由(以避免与Stack Overflow原则一致的讨论)?
编辑:“我还没有创建外键的理由,所以这可能是我真正建立一个外键的第一个理由。”
当前回答
在我参与的一个项目中,经常存在隐式关系而不是显式关系,这样可以在同一列上连接多个表。
请看下面的表格
地址
AddressId (PK) EntityId EntityType 城市 状态 国家 等。
EntityType的值可能是Employee、Company、Customer, EntityId指的是您感兴趣的表的主键。
我真的不认为这是最好的方法,但它对这个项目有效。
其他回答
我听到的观点是前端应该有这些业务规则。当您一开始就不应该允许任何破坏约束的插入时,外键会“增加不必要的开销”。我同意吗?不,但我一直都是这么听说的。
编辑:我猜他指的是外键约束,而不是外键这个概念。
有一个很好的理由不使用它们:如果你不了解它们的作用或如何使用它们。
在错误的情况下,外键约束可能导致事故的瀑布式复制。如果有人删除了错误的记录,恢复它可能会成为一项艰巨的任务。
同样,相反,当您需要删除某些内容时,如果设计不当,约束可能会导致各种锁阻止您的操作。
跨应用程序生命周期的可维护性和稳定性如何?大多数数据的生命周期都比使用它的应用程序长。关系和数据完整性非常重要,不能寄希望于下一个开发团队在应用程序代码中做出正确的处理。如果您没有使用过不尊重自然关系的脏数据的db,那么您将会使用。数据完整性的重要性将变得非常清楚。
更新:我现在总是使用外键。对于反对意见“他们使测试变得复杂”,我的回答是“编写单元测试,这样他们就根本不需要数据库。任何使用该数据库的测试都应该正确地使用它,这包括外键。如果准备工作很痛苦,那就找一种不那么痛苦的方式来做。”
外键使自动化测试复杂化
假设您正在使用外键。您正在编写一个自动测试,该测试表示“当我更新财务帐户时,它应该保存交易记录。”在这个测试中,您只关心两个表:帐户和事务。
但是,accounts对契约有一个外键,契约对客户有一个fk,客户对城市有一个fk,城市对州有一个fk。
现在,数据库将不允许您运行测试,除非在四个与测试无关的表中设置数据。
至少有两种可能的观点:
“这是一件好事:你的测试应该是现实的,这些数据限制将存在于生产中。” “这是一件坏事:你应该能够在不涉及其他部分的情况下对系统的各个部分进行单元测试。您可以为整个系统添加集成测试。”
也可以在运行测试时暂时关闭外键检查。至少MySQL支持这一点。
我只知道Oracle数据库,不知道其他数据库,而且我知道外键对于保持数据完整性是必不可少的。在插入数据之前,需要建立一个数据结构,并且建立正确的数据结构。当这一步完成时——所有的主键和外键都创建好了——工作就完成了!
意思是:孤立的行?不。这辈子都没见过。除非一个糟糕的程序员忘记了外键,或者他在另一个层次上实现了外键。在Oracle的环境中,这两者都是巨大的错误,会导致数据复制、孤儿数据,从而导致数据损坏。我无法想象一个没有强制FK的数据库。在我看来是一片混乱。这有点像Unix权限系统:假设每个人都是root用户。想想混乱吧。
外键是必不可少的,就像主键一样。这就像是说:如果我们移除主键会怎样?那么,整个混乱将会发生。这是什么。不能将主键或外键的职责移到编程级别,但必须移到数据级别。
缺点呢?是的,当然!因为在插入时,会有更多的检查。但是,如果数据完整性比性能更重要,那么这是显而易见的。Oracle上的性能问题更多地与索引有关,索引包含PK和FK。