没有外键的数据库设计

时间:2012-08-22 02:15:52

标签: sql database-design

在各个雇主工作之后,我注意到这些公司中部分的“糟糕”数据库设计趋势 - 主要是排除外键约束。它一直在告诉我这些交易系统没有FK,这会促进参照完整性。

  
      
  • 在交易系统中是否存在任何情况,即遗漏FK会有所帮助?

  •   
  • 有没有其他人经历过这种情况,如果有,结果是什么?

  •   
  • 如果他们遇到这种情况并被要求维护/增强系统,应该怎么做?

  •   

6 个答案:

答案 0 :(得分:36)

我无法想到任何场景,如果两列具有依赖关系,则它们之间不应设置FK约束。删除参照完整性可能肯定会加快数据库操作速度,但支付费用相当高。

已经经历过这样的系统,并且通常的结果是损坏的数据,在某种意义上存在不应该存在的记录(反之亦然)。这些是人们认为他们没事的系统,因为应用程序会处理它,而不是关心它:

  • 每个应用程序都必须处理它,而不是一个数据库服务器。
  • 只需要一个bug或恶意应用就可以为每个人搞砸了。
  • 数据库有责任保护本身!这是其最佳功能之一。

关于你应该做什么,我只是提出可能出错的事情,以及如何使用FK来防止这种情况(如果有必要,通常会对我的观点进行成本/收益分析“倾斜”)。然后让公司决定 - 毕竟这是他们的数据库。

答案 1 :(得分:8)

有一种观点认为,编写良好的应用程序不需要参照完整性。如果应用程序做正确的事情,那么就不需要约束了。

这种想法类似于不进行防御性编程,因为如果你正确编写代码,你就不会有bug。虽然如此,但根本不会发生。不使用适当的约束是要求数据损坏。

至于你应该做什么,你应该鼓励公司在每个机会都增加约束。你不想把它推到陷入困境或为自己做一个坏名声,但只要环境合适,继续推动它。从长远来看,每个人的生活都会更好。

答案 2 :(得分:5)

就个人而言,我对没有外键明确声明的数据库没有任何问题。但是,这取决于数据库的使用方式。

我使用的大多数数据库都是从一个或多个事务系统派生的相对静态数据。我并不特别关注影响数据库的恶意更新,因此外键关系的明确定义并不是特别重要。

我所拥有的一件事是非常一致的命名。基本上,每个表都有一个名为ID的第一列,这正是列在其他表中的引用方式(或者,当两个实体之间存在多个关系时,有时带有前缀)。我还试图坚持这样一个数据库中的每一列都有一个描述该属性的唯一名称(因此“CustomerStartDate”与“ProductStartDate”不同)。

如果我处理的数据中有更多“厨师在锅中”,那么我想更明确一下外键关系。然后,我更愿意承担外键定义的开销。

这种开销出现在很多地方。在创建新表时,我可能想使用“create table as”或“select into”而不用担心约束的细节。在运行更新或插入查询时,我可能不希望数据库开销检查我知道的确定的事情。但是,我必须强调,一致的命名会大大增加我对事情没有问题的信心。

显然,我的观点不是DBA,而是实践者。但是,表格之间的无效关系是我 - 或我团队的其他成员 - 几乎从来没有处理过。

答案 3 :(得分:3)

只要有一个单一的进入数据库的点,最终对于哪个"层"保持参照完整性。使用"内置图层"外键约束似乎最有意义,但如果你有一个坚如磐石的服务层负责同一件事,那么它有必要在必要时自由破坏规则。

我个人使用外键约束并设计我的应用程序,因此他们不必违反规则。具有保证参照完整性的关系数据更容易使用。

获得的性能可能相当于在db之外维护完整性所导致的性能损失。

答案 4 :(得分:1)

在OLTP数据库中,我能想到的唯一原因是你是否关心性能而不是数据完整性。在将行插入子表时强制执行FK需要在父表上进行索引查找,并且我可以想象可能存在极端情况,即使这种相对快速的索引搜索过多也是如此。例如,某种非常密集的日志记录,您可以使用不正确的日志条目,并且执行写入的应用程序很简单,并且不太可能存在错误。

话虽这么说,如果你能忍受腐败的数据,你可能首先没有数据库。

答案 5 :(得分:0)

如果您主要使用存储过程并且每个应用程序都使用这些存储过程,而不是编写自己的查询,那么使用外键进行防御性编程就可以工作。然后,您可以比标准外键更轻松,更灵活地对其进行控制。

我可以想到的一种情况是,外键约束不易使用,这是权限模块,其中可以按布尔值确定每个用户或每个组的权限。因此,权限表中的某些记录具有用户ID,而其他记录具有组ID。如果仍然需要外键约束,则对于相同的互斥信息,必须具有两个不同的字段,并将它们设置为null。意思是添加了另一个约束,说一个允许为空,但不能同时为空,并且三个字段的组合必须唯一,而不是两个字段(用户/组ID和权限ID)的组合。另一种选择是包含相同数据的两个单独的表,这意味着分别维护两个表。

但是在那种情况下,最好是将数据分开。在需要同一字段才能基于该记录中的其他数据连接到不同表的任何地方,都不能使用外部字段约束,而最好将约束保留在存储过程和视图中。