127

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

外键还有其他用途吗?我在这里错过了什么吗?

4

24 回答 24

108

外键有助于在数据级别强制执行参照完整性。它们还提高了性能,因为它们通常在默认情况下被索引。

于 2008-08-20T20:19:33.997 回答
63

外键还可以帮助程序员使用ON DELETE CASCADE. 这意味着如果您有一个包含用户的表和另一个包含订单或其他内容的表,那么删除用户可能会自动删除指向该用户的所有订单。

于 2008-08-20T20:22:36.530 回答
47

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

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

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

于 2008-08-20T20:24:09.350 回答
44

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

有一天,你会后悔的。不在设计基础和数据完整性上花费那么一点额外的时间是确保以后头痛的可靠方法。

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

为什么你认为这在现代语言 中变得困难甚至不可接受?

于 2008-08-20T22:29:43.060 回答
21

是的。

  1. 他们让你诚实
  2. 他们让新开发人员保持诚实
  3. 你可以做ON DELETE CASCADE
  4. 它们可以帮助您生成漂亮的图表来自我解释表格之间的链接
于 2008-08-20T20:37:08.820 回答
16

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

在我看来,做出这样的假设是一个非常糟糕的主意。一般来说,软件是非常错误的。

这就是重点,真的。开发人员无法把事情做好,因此确保数据库不会被坏数据填充是一件好事。

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

于 2008-08-20T20:35:10.730 回答
14

就个人而言,我赞成外键,因为它形式化了表之间的关系。我意识到您的问题预设了程序员没有引入会违反参照完整性的数据,但是我已经看到了太多违反数据参照完整性的实例,尽管是出于好意!

预先外键约束(又名声明性引用完整性或 DRI)花费大量时间使用触发器来实现这些关系。我们可以通过声明性约束形式化关系这一事实非常强大。

@John - 其他数据库可能会自动为外键创建索引,但 SQL Server 不会。在 SQL Server 中,外键关系只是约束。您必须单独在外键上定义索引(这可能会有所帮助。)

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

于 2008-08-20T20:35:18.793 回答
9

如果没有外键,如何判断不同表中的两条记录是相关的?

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

于 2008-08-20T20:24:15.513 回答
8

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

于 2008-08-22T15:40:17.847 回答
8

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

假设程序员实际上已经以正确的方式这样做了,那么我们真的需要外键的概念吗?

理论上,不会。然而,从来没有一个软件没有错误。

应用程序代码中的错误通常没有那么危险——您识别错误并修复它,然后应用程序再次顺利运行。但是如果一个错误允许损坏的数据进入数据库,那么你就被困住了!很难从数据库中的损坏数据中恢复。

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

在 Web 应用程序中,您通常只有一个程序与数据库通信,因此只有一个地方存在错误可以破坏数据。在企业应用程序中,可能有几个独立的应用程序与同一个数据库通信(更不用说直接使用数据库外壳的人)。没有办法确保所有应用程序都遵循相同的假设而没有错误,永远永远。

如果约束是在数据库中编码的,那么错误可能发生的最坏情况是向用户显示一条关于某些SQL约束不满足的丑陋错误消息。这让损坏的数据进入您的企业数据库更可取,因为它反过来会破坏您的所有应用程序,或者只是导致各种错误或误导性的输出。

哦,外键约束也提高了性能,因为它们是默认索引的。我想不出任何理由使用外键约束。

于 2008-09-17T13:24:52.090 回答
8

FK 非常重要,应该始终存在于您的架构中,除非您是 eBay

于 2009-04-19T14:53:11.497 回答
6

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

例如,Ruby on Rails不使用外键,但它自己验证所有关系。如果您只从那个 Ruby on Rails 应用程序访问您的数据库,那很好。

但是,如果您有其他客户端正在写入数据库,那么在没有外键的情况下,它们需要实现自己的验证。然后,您有两份很可能不同的验证代码副本,任何程序员都应该能够分辨出这是一个大罪。

那时,外键确实是必要的,因为它们允许您再次将责任转移到一个点。

于 2008-08-20T20:28:30.590 回答
5

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

现在一切可能都很好,但想想当你的程序员离开而其他人必须接管时会发生什么。

外键将允许他们理解数据库结构,而无需翻阅数千行代码。

于 2008-09-17T04:44:39.237 回答
5

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

FK 允许 DBA 在程序员未能做到这一点时保护数据完整性免受用户的摸索,有时还可以防止程序员摸索。

假设程序员实际上已经以正确的方式这样做了,那么我们真的需要外键的概念吗?

程序员是必死的,也是容易犯错的。FK 是声明性的,这使得它们更难搞砸。

外键还有其他用途吗?我在这里错过了什么吗?

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

于 2008-10-06T21:26:50.257 回答
4

它们不是绝对必要的,就像安全带不是绝对必要的那样。但是它们确实可以使您免于做一些弄乱数据库的愚蠢行为。

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

于 2008-08-20T20:57:14.543 回答
4

它们很重要,因为您的应用程序并不是在数据库中操作数据的唯一方式。您的应用程序可以按照自己的意愿诚实地处理引用完整性,但只需要一个具有正确权限的笨蛋出现并在数据库级别发出插入、删除或更新命令,并且您的所有应用程序引用完整性强制执行都被绕过了。将 FK 约束放入数据库级别意味着,除非这个笨蛋在发出命令之前选择禁用 FK 约束,否则 FK 约束将导致错误的插入/更新/删除语句因违反参照完整性而失败。

于 2008-09-17T19:09:02.373 回答
3

我从成本/收益的角度考虑它......在MySQL中,添加约束是DDL的一个附加行。这只是几个关键词和几秒钟的思考。在我看来,这是唯一的“成本”......

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

当你把东西放在一起时,把你脑子里已经存在的东西编成代码所花费的时间很短,可以为你或其他人节省几个月或几年的痛苦。

问题:

外键还有其他用途吗?我在这里错过了什么吗?

它有点加载。插入注释、缩进或变量命名来代替“外键”……如果你已经完全理解了这个问题,那对你来说“没用”。

于 2008-08-21T03:30:57.187 回答
2

熵减少。减少数据库中出现混乱场景的可能性。我们遇到了困难,因为它正在考虑所有可能性,所以在我看来,熵减少是任何系统维护的关键。

例如,当我们做出假设时:每个订单都有一个客户,该假设应该由某事强制执行。在数据库中,“某物”是外键。

我认为这值得在开发速度上进行权衡。当然,您可以在关闭它们的情况下更快地编写代码,这可能就是有些人不使用它们的原因。就我个人而言,我已经用NHibernate和一些外键约束杀死了几个小时,当我执行一些操作时它们会生气。但是,我知道问题出在哪里,所以问题不大。我正在使用普通工具,并且有资源可以帮助我解决这个问题,甚至可能有人来帮忙!

另一种方法是允许错误潜入系统(如果有足够的时间,它会),其中未设置外键并且您的数据变得不一致。然后,你得到一个不寻常的错误报告,调查并“哦”。数据库搞砸了。现在需要多长时间才能修复?

于 2009-12-01T23:22:28.150 回答
1

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

  • 帮助维护数据完整性
  • 显示数据如何相互关联(这有助于执行业务逻辑和规则)
  • 如果使用得当,可以帮助提高从表中提取数据的效率。
于 2008-08-20T20:26:21.607 回答
1

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

也就是说 - 我们可能会在不久的将来开始更多地使用它们,原因有几个,两者都有相似的原因:

  1. 绘图。如果正确使用了外键关系,则生成数据库图表会容易得多。

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

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

于 2008-08-20T20:55:32.600 回答
1

外键约束(实际上是一般约束)的最佳之处在于,您可以在编写查询时依赖它们。如果您不能依赖保持“真”的数据模型,很多查询可能会变得更加复杂。

在代码中,我们通常只会在某处抛出异常——但在SQL中,我们通常只会得到“错误”的答案。

理论上,SQL Server可以使用约束作为查询计划的一部分——但除了分区检查约束之外,我不能说我曾经亲眼目睹过这一点。

于 2008-08-20T22:10:22.670 回答
1

在我从事的项目(业务应用程序和社交网络网站)中,外键从未明确声明过(FOREIGN KEY REFERENCES table(column))。

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

就像数据库规范化一样——你必须知道你在做什么以及这样做的后果是什么(主要是性能)。

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

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

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

于 2008-08-21T09:06:22.827 回答
0

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

幸运的是,我找到了这些:http://www.redhillonrails.org/foreign_key_associations.html -- RedHill on Ruby on Rails 插件使用约定优于配置样式生成外键。带有product_id的迁移将在products表 中为id创建一个外键。

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

于 2008-09-17T04:30:15.200 回答
0

如果您计划生成数据访问代码,即实体框架或任何其他 ORM,您将完全失去生成没有外键的分层模型的能力

于 2020-02-05T17:16:59.333 回答