数据库设计中真的需要外键吗?


109

据我所知,外键(FK)用于帮助程序员以正确的方式操作数据。假设程序员实际上已经在以正确的方式执行此操作,那么我们真的需要外键的概念吗?

外键还有其他用途吗?我在这里想念什么吗?


2
这经常在这里出现。我责怪Joel Spolsky :-)。这里有很多好的答案;而不是重新输入我的密码,我只给您链接:stackoverflow.com/questions/83147/whats-wrong-with-foreign-keys
SquareCog

70
“假设程序员实际上已经在以正确的方式执行此操作”-我什至无法想象这种情况。
递归

11
“外键”是一个想法,而不是技术。这是一个关系规则。您的问题实际上是关于您是应该尝试在代码中强制执行规则还是让数据库来帮助您。当涉及到并发时,最好让数据库引擎执行该规则,因为它知道数据库中发生的所有事情,而您的代码却可能不知道。
Triynko,2009年

5
@lubos和cdeszaq。实际上,这是一个关系规则...它是Codd的“ Twleve诫命”规则10的子集...“完整性独立性”,它基本上说RDBMS的关系完整性必须独立于访问它的任何应用程序来维护,正是我以一种易于理解的方式解释的内容。除其他外,此规则是通过外键约束来实现的。因此,是的,外键的概念是“ a”关系规则。
Triynko 2010年

1
@lubos:澄清一下,您正在谈论是否要使用特定功能,但是我正在谈论是否必须具有该功能才能拥有完整的,功能齐全的RDBMS。引用约束(如果以及当您选择使用它们时)是应该在RDBMS(而不是应用程序)中强制执行的东西,因此它应该是其中的一项功能,从某种意义上说,这是关系模型的要求您将要开发一个完整的RDBMS。
Triynko 2010年

Answers:


102

外键有助于在数据级别上实现引用完整性。它们还提高了性能,因为通常默认情况下对它们进行索引。


52
如果您需要创建一个索引,则这不是FK的主要原因。(实际上,在某些情况下(例如,插入内容多于选择内容)维护FK可能会更慢。)
罗伯特·罗伯特(Robert

7
这是FK可怕的答案,它会增加额外的开销而不改善性能。
敏捷绝地

在SQL Server中,默认情况下,不会在裁判或引荐来源上为它们建立索引。 sqlskills.com/blogs/kimberly/...
user420667

1
甲骨文公司也没有;您必须自己创建索引(在FK列上)。
Littlefoot '18

58

外键还可以帮助程序员使用诸如之类的代码编写更少的代码ON DELETE CASCADE。这意味着,如果您有一个包含用户的表,而另一个包含订单或其他东西的表,那么删除用户可以自动删除所有指向该用户的订单。


3
@Greg Hewgill这可能会潜在地导致很多问题。您应该非常谨慎地对待DELETE CASCADE之类的想法,因为在许多情况下,删除用户时,您希望保留用户创建的订单。
Kibbee

8
尽管这可能应该在业务逻辑层中处理。决定是否保留相关的子记录与确保没有值违反外键关系并不完全相同。
Codewerks

5
另一个问题是审计,如果未在数据库级别上进行审计,则级联的更新或删除将使您的审计跟踪无效。
2009年

@Codewerks:业务逻辑可以在数据库中。
Fantius 2011年

44

我无法想象设计没有外键的数据库。没有它们,最终您必定会犯一个错误并破坏数据的完整性。

严格来讲,它们不是必需的,但是好处是巨大的。

我相当确定FogBugz在数据库中没有外键约束。我想听听Fog Creek软件团队如何构建代码以确保他们永远不会引入不一致之处。


43
乔尔:“到目前为止,我们从未遇到过问题。” 到目前为止,我还没有遇到过路灯柱。但是我仍然认为系好安全带是个好主意;-)
托尼·安德鲁斯

2
可能是您从未见过问题,但可能是那里...大多数数据库都使用id_xxx之类的约定,该约定与ixXXX完全相同
FerranB

1
@Joel:用命名约定代替规则的执行?在您打字时也可以取消打字。
jcollum

8
@Eric:您在这里将Fog Creek当作某种软件开发的化身。如果您说“纽约市的公司的数据库中没有外键...”,我们都会说“并且?”
jcollum

3
埃里克(Eric):FogBugz对外键使用命名约定。例如,ixBug被理解为表Bug的主键的索引。到目前为止,我们从未遇到过问题。-Joel Spolsky
Sam Saffron'2

40

没有FK约束的数据库模式就像没有安全带的驾驶。

有一天,你会后悔的。不花一点额外的时间在设计基础知识和数据完整性上,无疑是确保以后麻烦的有效方法。

您会在应用程序中接受如此草率的代码吗?直接访问成员对象并直接修改数据结构。

您为什么认为在现代语言中这变得很难甚至无法接受


2
+1是封装与FK / PK关系之间的良好比喻。
jcollum

21

是。

  1. 他们让你诚实
  2. 他们让新开发者诚实
  3. 你可以做 ON DELETE CASCADE
  4. 它们可以帮助您生成漂亮的图表,这些图表可以自我解释表之间的链接

1
诚实是什么意思?
dspacejs 2015年

我猜对这个概念很诚实。通过快速而and脚的编程,可以防止您欺骗数据。
奥雷斯特·维隆

13

假设程序员实际上已经以正确的方式执行此操作

在我看来,做出这样的假设是一个非常糟糕的主意。一般而言,软件是令人难以置信的错误。

的确如此。开发人员无法正确解决问题,因此确保数据库中不会填充不良数据是一件好事。

尽管在理想情况下,自然联接将使用关系(即FK约束)而不是匹配列名。这将使FK更加有用。


2
好点,用“ ON [Relationship]”或其他关键字联接两个表,并让数据库确定涉及哪些列,这将是很好的。似乎真的很合理。
jcollum

13

就个人而言,我赞成使用外键,因为它使表之间的关系正式化。我意识到您的问题以程序员没有引入会破坏参照完整性为前提的数据为前提,但是我看到了太多的例子,尽管有最好的意图,但这些数据违反了参照完整性。

前外键约束(又称为声明性引用完整性或DRI)花费了大量时间使用触发器来实现这些关系。我们可以通过声明性约束将关系形式化的事实非常有力。

@John-其他数据库可能会自动为外键创建索引,但是SQL Server不会。在SQL Server中,外键关系仅是约束。您必须分别在外键上定义索引(这很有用。)

编辑:我想补充一点,IMO,使用外键来支持ON DELETE或ON UPDATE CASCADE不一定是一件好事。在实践中,我发现应该根据数据之间的关系仔细考虑级联删除操作,例如,您是否有一个自然的父子级关系,或者相关表是一组查找值?使用级联更新意味着您允许修改一个表的主键。在那种情况下,我有一个普遍的哲学分歧,那就是表的主键不应更改。键本质上应该是恒定的。


9

没有外键,您如何分辨不同表中的两个记录是相关的?

我认为您指的是参照完整性,即在没有现有父记录等的情况下不允许创建子记录。这些通常称为外键约束-请勿与外键的存在混淆第一名。


8

不用外键有好处吗?除非您使用糟糕的数据库,否则FK的设置并不难。那么,为什么要制定避免使用它们的政策?命名约定说一列引用另一列是一回事,知道数据库实际上正在为您验证这种关系是另一回事。


8

我想您正在谈论数据库强制执行的外键约束。您可能已经在使用外键,只是没有告诉数据库。

假设程序员实际上已经在以正确的方式执行此操作,那么我们真的需要外键的概念吗?

从理论上讲,不会。但是,从来没有一款软件没有错误。

应用程序代码中的错误通常没有那么危险-确定并修复该错误,然后应用程序可以再次平稳运行。但是,如果一个错误允许不可靠的数据进入数据库,那么您就被它困住了!从数据库中的损坏数据中恢复非常困难。

考虑一下FogBugz中的一个细微错误是否允许将损坏的外键写入数据库。修正错误并在修正版本中快速将修正推向客户很容易。但是,如何解决数十个数据库中的损坏数据?正确的代码现在可能突然中断,因为关于外键完整性的假设不再成立。

在Web应用程序中,通常只有一个程序与数据库对话,因此,只有一个地方错误可能破坏数据。在企业应用程序中,可能有几个独立的应用程序与同一个数据库对话(更不用说直接与数据库外壳一起工作的人了)。没有办法确保所有应用程序都遵循相同的假设,并且始终存在错误。

如果约束是在数据库中编码的,则错误可能发生的最糟糕的情况是,向​​用户显示关于某些SQL约束未满足的丑陋错误消息。这是很多 prefereable又让currupt数据到企业数据库,它反过来会打破所有的应用程序,或只是导致各种错误或误导性的输出。

哦,外键约束也可以提高性能,因为默认情况下会对其进行索引。我想不出任何理由使用外键约束。


7

FK非常重要,除非您是eBay否则 FK应该始终存在于您的模式


2
该链接实际上非常引人入胜...我真的很想知道更多细节,现在我有点害怕使用ebay。对于其他人:单击第四个问题,以查看他对他们的数据库结构的看法。不过,整个采访值得一看。还...unibrow
gloomy.penguin

6

我认为某些时候某些事情必须负责确保有效的关系。

例如,Ruby on Rails不使用外键,但是它会验证所有关系本身。如果您只从该Ruby on Rails应用程序访问数据库,那很好。

但是,如果您有其他正在写入数据库的客户端,则没有外键,它们需要实现自己的验证。然后,您将获得验证码的两个副本,它们很可能是不同的,任何程序员都应该知道这是一个主要的罪过。

到那时,确实需要外键,因为它们使您可以将职责再次移至单个点。


2
就像洋葱。FK是防御的最后一层。除非它是嵌入式本地数据库,否则尝试实现引用完整性的应用程序始终不是一个好主意。
Fabricio Araujo 2013年

5

外键使以前没有看过您数据库的人可以确定表之间的关系。

现在一切可能都很好,但是请考虑一下,当您的程序员离职而其他人必须接管时会发生什么。

外键将使他们能够理解数据库结构,而无需浏览数千行代码。


5

据我所知,外键用于帮助程序员以正确的方式操作数据。

FK允许DBA在程序员这样做时保护数据完整性,以防止用户感到困惑,有时还可以防止程序员感到困惑。

假设程序员实际上已经在以正确的方式执行此操作,那么我们真的需要外键的概念吗?

程序员是凡人,容易犯错误。FK是声明性的,这使它们更难搞砸。

外键还有其他用途吗?我在这里想念什么吗?

尽管这不是创建它们的原因,但是FK为图表工具和查询生成器提供了可靠的可靠提示。这将传递给最终用户,他们迫切需要强大的可靠提示。


这是一个很好的答案。
Dan Lugg 2013年

4

安全带不是绝对必要的,因此不是绝对必要的。但是它们确实可以使您免于愚蠢地使数据库混乱。

调试FK约束错误比重新构造破坏应用程序的删除要好得多。


4

它们很重要,因为您的应用程序不是在数据库中操作数据的唯一方式。您的应用程序可以按需要诚实地处理引用完整性,但是只需一个具有适当权限的bozo即可在数据库级别发出插入,删除或更新命令,并且所有应用程序引用完整性强制都将被绕开。将FK约束放在数据库级别意味着,除非在发出命令之前选择禁用该FK约束,否则FK约束将导致错误的insert / update / delete语句失败,并导致参照完整性冲突。


3

我从成本/收益方面考虑...在MySQL中,添加约束是DDL的另外一行。这只是几个关键词和几秒钟的思考。我认为这是唯一的“成本”。

工具喜欢外键。外键可防止可能不会影响业务逻辑或功能的不良数据(即孤立的行),因此不会引起注意并堆积。这还可以防止不熟悉该架构的开发人员实现整个工作块,而不会意识到他们之间缺少关系。也许在当前应用程序的范围内,一切都很好,但是如果您错过了某些东西,并且有一天又添加了一些意外的东西(想想报告),您可能就需要手动清理自开始以来就积累的不良数据。无需数据库强制检查的模式。

将事情整理在一起时,花很少的时间整理头脑中已有的内容,可以为您或其他人节省数月或数年的痛苦。

问题:

外键还有其他用途吗?我在这里想念什么吗?

它有点加载。插入注释,缩进或变量命名来代替“外键” ...如果您已经完全理解了所要解决的问题,那么这对您“毫无用处”。


2

熵减少。减少数据库中发生混乱情况的可能性。考虑到所有可能的目标,我们都遇到了困难,因此,我认为,减少熵是维护任何系统的关键。

例如,当我们进行假设时:每个订单都有一个客户,该假设应由某种东西来执行。在数据库中,“某物”是外键。

我认为这值得在开发速度上进行权衡。当然,您可以在不使用它们的情况下更快地编写代码,这可能就是为什么某些人不使用它们的原因。就我个人而言,我已经使用NHibernate消磨了几个小时,并且某些外键约束在执行某些操作时会很生气。但是,我知道问题出在哪里,所以问题不大。我使用的是常规工具,并且有很多资源可以帮助我解决此问题,甚至可能有人需要帮助!

替代方法是允许错误爬入未设置外键且数据变得不一致的系统中(并且有足够的时间,它将进入系统)。然后,您将得到一个异常的错误报告,进行调查并“ OH”。数据库被搞砸了。现在要花多长时间才能解决?


1

您可以将外键视为一种约束,

  • 帮助维持数据完整性
  • 显示数据如何相互关联(这有助于执行业务逻辑和规则)
  • 如果正确使用,可以帮助提高从表中提取数据的效率。

1

我们目前不使用外键。在大多数情况下,我们不后悔。

话虽如此-我们出于各种原因可能会在不久的将来开始大量使用它们,而这两个原因都有相似之处:

  1. 图解。如果正确使用了外键关系,那么生成数据库图表就容易得多。

  2. 工具支持。如果存在适当的外键关系,则使用Visual Studio 2008建立可用于LINQ to SQL的数据模型要容易得多

所以我想我的意思是,我们发现,如果我们在做大量手动SQL工作(构造查询,运行查询,等等),外键不一定是必需的。但是,一旦您开始使用工具,它们就会变得有用得多。


1
我在不使用它们的系统上工作。我经常后悔。我看到了更多的实例,我可以算出适当的约束可以避免的非实际数据。
递归

我已经与外键在我们当前的项目中合作了将近六个月,我完全同意这一评论。
约翰·克里斯滕森

1

关于外键约束(实际上确实是约束)的最好之处在于,编写查询时可以依赖它们。如果您不依赖于数据模型为“ true”,那么很多查询就会变得更加复杂。

在代码中,通常只会在某处引发异常-但是在SQL中,通常只会得到“错误”答案。

从理论上讲,SQL Server可以将约束用作查询计划的一部分-但是除了用于分区的检查约束之外,我不能说我曾经亲眼目睹过。


唯一性约束指示高基数,优化器在选择连​​接机制时会使用该基数。
Peter Wone

1

我从事过的项目(业务应用程序和社交网站)中从未声明过外键(FOREIGN KEY REFERENCES表(列))。

但是,总是有一种命名列的约定,即外键。

就像数据库规范化一样,您必须知道自己在做什么以及这样做的结果(主要是性能)。

我知道外键的优点(数据完整性,外键列的索引,知道数据库模式的工具),但是我也害怕将外键用作一般规则。

同样,各种数据库引擎可以以不同的方式提供外键,这可能会导致在迁移过程中产生细微的错误。

使用ON DELETE CASCADE删除已删除客户端的所有订单和发票是外观漂亮但设计错误的数据库架构的完美示例。


0

是。ON DELETE [RESTRICT | CASCADE]阻止开发人员搁浅数据,保持数据干净。我最近加入了一个Rails开发人员团队,他们不关注外键等数据库约束。

幸运的是,我发现了这些:http ://www.redhillonrails.org/foreign_key_associations.html-Ruby on Rails插件上的RedHill使用约定优于配置样式来生成外键。与迁移的product_id将创建一个外键ID产品表中。

RedHill上查看其他出色的插件,包括打包在事务中的迁移。


0

如果计划生成数据访问代码(例如,Entity Framework或任何其他ORM),那么您将完全失去生成没有外键的层次模型的能力

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.