269

我记得在播客 014中听到Joel Spolsky提到他几乎没有使用过外键(如果我没记错的话)。但是,对我来说,它们对于避免整个数据库中的重复和后续数据完整性问题似乎非常重要。

人们是否有充分的理由说明原因(以避免根据堆栈溢出原则进行讨论)?

编辑: “我还没有理由创建外键,所以这可能是我实际设置外键的第一个原因。”

4

38 回答 38

372

使用外键的原因:

  • 你不会得到孤立的行
  • 您可以获得很好的“删除级联”行为,自动清理表
  • 了解数据库中表之间的关系有助于优化器计划您的查询以最有效地执行,因为它能够更好地估计连接基数。
  • FK 对在数据库上收集哪些统计信息最重要提供了相当大的提示,这反过来又会带来更好的性能
  • 它们支持各种自动生成的支持——ORM 可以自己生成,可视化工具能够为您创建漂亮的模式布局,等等。
  • 刚接触项目的人会更快地进入事物的流程,因为否则隐含的关系会被明确记录

不使用外键的原因:

  • 您正在使数据库在每个CRUD操作上额外工作,因为它必须检查 FK 一致性。如果您有很多客户流失,这可能是一笔不小的开支
  • 通过强制执行关系,FK 指定了您必须添加/删除事物的顺序,这可能导致数据库拒绝执行您想要的操作。(当然,在这种情况下,您要做的是创建一个孤立行,这通常不是一件好事)。当您进行大批量更新时,这尤其痛苦,并且您先加载一个表,而第二个表创建一致的状态(但是如果第二个加载可能失败并且您的数据库现在不一致?)。
  • 有时你事先知道你的数据会变脏,你接受它,你希望数据库接受它
  • 你只是懒惰:-)

我认为(我不确定!)大多数已建立的数据库都提供了一种方法来指定未强制执行的外键,并且只是一些元数据。由于不强制执行消除了不使用 FK 的所有理由,如果第二部分中的任何原因适用,您可能应该走这条路。

于 2008-09-17T13:46:37.390 回答
83

这是教养的问题。如果在你的教育或职业生涯的某个地方,你花时间喂养和关心数据库(或与这样做的有才华的人密切合作),那么实体和关系的基本原则在你的思维过程中根深蒂固。其中包括如何/何时/为什么指定数据库中的键(主键、外键,可能还有备用键)。这是第二天性。

但是,如果您过去在与 RDBMS 相关的工作中没有如此彻底或积极的经验,那么您可能没有接触过此类信息。或者您的过去可能包括沉浸在一个强烈反对数据库的环境中(例如,“那些 DBA 是白痴 - 我们很少,我们选择了几个 java/c# 代码吊索将拯救这一天”),在这种情况下,您可能会强烈反对一些 dweeb 神秘的喋喋不休告诉你,如果你只是听,FKs(以及它们可能暗示的约束)真的很重要。

大多数人小时候都被教导刷牙很重要。没有它你能过得去吗?当然可以,但是在某个地方,如果您在每餐后刷牙,您可用的牙齿会更少。如果妈妈和爸爸足够负责数据库设计和口腔卫生,我们就不会进行这样的对话。:-)

于 2008-09-17T16:55:17.437 回答
54

我确信有很多应用程序可以让你摆脱它,但这不是最好的主意。您不能总是指望您的应用程序来正确管理您的数据库,坦率地说,管理数据库不应该是您的应用程序非常关心的问题。

如果您使用的是关系数据库,那么您似乎应该在其中定义一些关系。不幸的是,这种态度(您不需要外键)似乎被许多应用程序开发人员所接受,他们宁愿不为诸如数据完整性之类的愚蠢事情而烦恼(但需要这样做,因为他们的公司没有专门的数据库开发人员)。通常在由这些类型组合在一起的数据库中,您很幸运只有主键;)

于 2008-09-17T13:38:10.450 回答
42

Foreign keys are essential to any relational database model.

于 2008-09-17T13:29:34.013 回答
29

我总是使用它们,但后来我为金融系统制作数据库。数据库是应用程序的关键部分。如果财务数据库中的数据不完全准确,那么您在代码/前端设计中投入多少精力并不重要。你只是在浪费时间。

还有一个事实是,多个系统通常需要直接与数据库交互——从其他只读取数据的系统(Crystal Reports)到插入数据的系统(不一定使用我设计的 API;它可能由刚刚发现 VBScript 并拥有 SQL 框的 SA 密码的愚蠢经理)。如果数据库不像它可能的那样防白痴,那么,再见了数据库。

如果您的数据很重要,那么是的,使用外键,创建一套存储过程来与数据交互,并尽可能制作最坚固的数据库。如果您的数据不重要,为什么要从创建数据库开始?

于 2008-09-17T13:40:21.943 回答
22

更新:我现在总是使用外键。我对“他们使测试复杂”的反对意见的回答是“编写你的单元测试,这样他们就根本不需要数据库。任何使用数据库的测试都应该正确使用它,并且包括外键。如果设置很痛苦,找到一种不那么痛苦的方法来进行设置。”


外键使自动化测试复杂化

假设您正在使用外键。你正在编写一个自动化测试,上面写着“当我更新一个财务账户时,它应该保存交易记录。” 在这个测试中,您只关心两个表:accountstransactions.

但是,accounts有一个外键到contracts,并且contracts有一个 fk 到clients,并且clients有一个 fk 到cities,并且cities有一个 fk 到states

现在数据库将不允许您在未在与您的测试无关的四个表中设置数据的情况下运行您的测试

对此至少有两种可能的观点:

  • “这是一件好事:你的测试应该是现实的,并且这些数据约束将存在于生产中。”
  • “这是一件坏事:你应该能够在不涉及其他部分的情况下对系统的各个部分进行单元测试。你可以为整个系统添加集成测试。”

也可以在运行测试时暂时关闭外键检查。MySQL 至少支持这个

于 2012-10-26T13:11:25.317 回答
16

“它们会使删除记录变得更加麻烦——你不能删除“主”记录,因为在其他表中存在外键会违反该约束的记录。”

请务必记住,SQL 标准定义了在删除或更新外键时采取的操作。我知道的有:

  • ON DELETE RESTRICT- 防止删除其他表中在此列中具有键的任何行。这就是上面肯·雷所描述的。
  • ON DELETE CASCADE- 如果另一个表中的行被删除,请删除该表中引用它的所有行。
  • ON DELETE SET DEFAULT- 如果另一个表中的一行被删除,请将引用它的任何外键设置为该列的默认值。
  • ON DELETE SET NULL- 如果另一个表中的行被删除,则将该表中引用它的任何外键设置为空。
  • ON DELETE NO ACTION- 这个外键只标明它是外键;即用于 OR 映射器。

这些相同的操作也适用于ON UPDATE.

默认值似乎取决于您使用的

于 2008-09-17T13:59:23.443 回答
14

@imphasing - 这正是导致维护噩梦的心态。

为什么哦,为什么您会忽略声明性引用完整性,其中可以保证数据至少是一致的,而支持所谓的“软件执行”,这充其量只是一种薄弱的预防措施。

于 2008-09-17T13:36:15.107 回答
12

不使用它们有一个很好的理由: 如果您不了解它们的作用或如何使用它们。

在错误的情况下,外键约束可能导致意外的瀑布式复制。如果有人删除了错误的记录,撤消它可能会成为一项艰巨的任务。

同样,相反,当您需要删除某些东西时,如果设计不当,约束可能会导致各种阻止您的锁定。

于 2008-09-17T13:34:04.813 回答
10

There are no good reasons not to use them... unless orphaned rows aren't a big deal to you I guess.

于 2008-09-17T13:27:57.793 回答
8

“在添加记录之前,检查另一个表中是否存在对应的记录”是业务逻辑。

以下是您不希望在数据库中使用它的一些原因:

  1. 如果业务规则发生变化,则必须更改数据库。在很多情况下,数据库需要重新创建索引,这在大表上很慢。(更改规则包括:允许客人发布消息或允许用户删除他们的帐户,尽管已经发布了评论等)。

  2. 更改数据库并不像通过将更改推送到生产存储库来部署软件修复那么容易。我们希望尽可能避免改变数据库结构。数据库中的业务逻辑越多,您就越有可能需要更改数据库(并触发重新索引)。

  3. TDD。在单元测试中,您可以用数据库代替模拟并测试功能。如果您的数据库中有任何业务逻辑,则您没有进行完整的测试,并且需要使用数据库进行测试或在代码中复制业务逻辑以进行测试,复制逻辑并增加逻辑在数据库中不起作用的可能性同样的方法。

  4. 使用不同的数据源重用您的逻辑。如果数据库中没有逻辑,我的应用程序可以从数据库中的记录创建对象,从 Web 服务、json 文件或任何其他来源创建它们。我只需要换出数据映射器实现,就可以将我所有的业务逻辑与任何源一起使用。如果数据库中有逻辑,这是不可能的,您必须在数据映射层或业务逻辑中实现逻辑。无论哪种方式,您都需要在代码中进行这些检查。如果数据库中没有逻辑,我可以使用不同的数据库或平面文件实现将应用程序部署在不同的位置。

于 2018-01-12T13:23:51.337 回答
5

根据我的经验,最好避免在数据库关键应用程序中使用 FK。我不会不同意这里的人说 FK 是一种很好的做法,但在数据库很大并且每秒有大量 CRUD 操作的情况下它是不切实际的。我可以不命名分享......最大的投资银行之一在数据库中没有一个 FK。这些约束由程序员在创建涉及 DB 的应用程序时处理。基本原因是,当一个新的 CRUD 完成时,它必须影响多个表并验证每个插入/更新,尽管这对于影响单行的查询来说不是一个大问题,但是当你处理时它确实会产生巨大的延迟任何大型银行都必须作为日常任务进行的批处理。

最好避免 FK,但它的风险必须由程序员来处理。

于 2014-10-13T10:02:02.170 回答
4

更大的问题是:你会戴着眼罩开车吗?如果您开发一个没有引用约束的系统,情况就是这样。请记住,业务需求更改、应用程序设计更改、代码中的相应逻辑假设更改、逻辑本身可以重构等等。通常,数据库中的约束是在当代逻辑假设下设置的,对于特定的逻辑断言和假设集似乎是正确的。

在应用程序的整个生命周期中,引用和数据检查限制了通过应用程序收集数据,尤其是当新需求推动逻辑应用程序更改时。

对于这个清单的主题——从实时事务处理系统的角度来看,外键本身不会“提高性能”,也不会显着“降低性能”。但是,在高容量“批处理”系统中进行约束检查会产生总成本。因此,这是实时与批量交易过程的区别;批处理 - 由约束检查引起的按顺序处理的批处理的总成本会对性能造成影响。

在一个设计良好的系统中,数据一致性检查将在处理批次“之前”完成(尽管如此,这里也有相关的成本);因此,在加载期间不需要外键约束检查。事实上,所有约束,包括外键,都应该暂时禁用,直到批处理完成。

查询性能- 如果表是在外键上连接的,请注意外键列不是索引的事实(尽管相应的主键是按定义索引的)。就此而言,通过索引外键,通过索引任何键,并在索引上连接表有助于提高性能,而不是通过连接具有外键约束的非索引键。

更改主题,如果数据库仅支持网站显示/呈现内容/等和记录点击,那么对所有表具有完全约束的数据库对于此类目的来说是过度的。想想看。大多数网站甚至不为此使用数据库。对于类似的要求,如果数据只是被记录而不是被引用,请使用没有约束的内存数据库。这并不意味着没有数据模型,是逻辑模型,但没有物理数据模型。

于 2009-10-04T05:52:43.437 回答
3

I agree with the previous answers in that they are useful to mantain data consistency. However, there was an interesting post by Jeff Atwood some weeks ago that discussed the pros and cons of normalized and consistent data.

In a few words, a denormalized database can be faster when handling huge amounts of data; and you may not care about precise consistency depending on the application, but it forces you to be much more careful when dealing with data, as the DB won't be.

于 2008-09-17T13:33:40.713 回答
3

Clarify 数据库是没有主键或外键的商业数据库的示例。

http://www.geekinterview.com/question_details/18869

有趣的是,技术文档不遗余力地解释表是如何相关的,使用哪些列来连接它们等。

换句话说,他们本可以使用显式声明 (DRI) 连接表,但他们选择不这样做

因此,Clarify 数据库充满了不一致,并且表现不佳。

但我想它使开发人员的工作更轻松,不必编写代码来处理引用完整性,例如在删除、添加之前检查相关行。

我认为,这是关系数据库中没有外键约束的主要好处。它使开发更容易,至少从不顾一切的角度来看是这样。

于 2008-09-17T13:34:29.447 回答
2

They can make deleting records more cumbersome - you can't delete the "master" record where there are records in other tables where foreign keys would violate that constraint. You can use triggers to have cascading deletes.

If you chose your primary key unwisely, then changing that value becomes even more complex. For example, if I have the PK of my "customers" table as the person's name, and make that key a FK in the "orders" table", if the customer wants to change his name, then it is a royal pain... but that is just shoddy database design.

I believe the advantages in using fireign keys outweighs any supposed disadvantages.

于 2008-09-17T13:31:08.470 回答
2

使用外键的其他原因: - 允许更多地重用数据库

不使用外键的其他原因: - 您试图通过减少重用来将客户锁定到您的工具中。

于 2008-09-17T15:17:56.780 回答
2

验证外键约束需要一些 CPU 时间,因此有些人会省略外键以获得额外的性能。

于 2008-09-17T13:34:15.623 回答
2

我只知道 Oracle 数据库,不知道其他数据库,而且我知道外键对于维护数据完整性至关重要。在插入数据之前,需要制作一个数据结构,并正确制作。完成后——因此创建了所有主键和外键——工作就完成了!

含义:孤立行?不,在我的生活中从未见过。除非一个糟糕的程序员忘记了外键,或者他在另一个层面上实现了它。两者都是 - 在 Oracle 的上下文中 - 巨大的错误,这将导致数据重复、孤立数据,从而:数据损坏。我无法想象没有强制执行 FK 的数据库。对我来说,这看起来很混乱。这有点像 Unix 权限系统:想象每个人都是 root。想想混乱。

外键是必不可少的,就像主键一样。这就像说:如果我们删除主键怎么办?好吧,完全的混乱将会发生。就是这样。您不能将主键或外键职责移至编程级别,它必须在数据级别。

缺点 ?是的,一点没错 !因为在插入时,将会发生更多的检查。但是,如果数据完整性比性能更重要,那就不费吹灰之力了。Oracle 的性能问题与 PK 和 FK 附带的索引更相关。

于 2014-11-23T14:01:56.697 回答
2

如果您绝对确定,一个底层数据库系统将来不会改变,我会使用外键来确保数据完整性。

但这是另一个完全不使用外键的非常好的现实理由:

您正在开发一个产品,它应该支持不同的数据库系统。

如果您正在使用能够连接到许多不同数据库系统的实体框架,您可能还希望支持“开源免费”无服务器数据库。并非所有这些数据库都支持您的外键规则(更新、删除行......)。

这可能会导致不同的问题:

1.) 创建或更新数据库结构时,您可能会遇到错误。也许只会有静默错误,因为您的外键只是被数据库系统忽略了。

2.)如果您依赖外键,您可能会在业务逻辑中进行更少甚至没有数据完整性检查。现在,如果新的数据库系统不支持这些外键规则或只是以不同的方式运行,您必须重写您的业务逻辑。

你可能会问:谁需要不同的数据库系统?好吧,并不是每个人都能买得起或想要在他的机器上安装一个完整的 SQL-Server。这是软件,需要维护。其他人已经在其他一些数据库系统上投入了时间和金钱。无服务器数据库非常适合仅在一台机器上使用的小客户。

没有人知道所有这些数据库系统的行为方式,但是您的业务逻辑以及完整性检查始终保持不变。

于 2015-09-14T13:16:57.490 回答
1

我还认为外键在大多数数据库中都是必需的。唯一的缺点(除了强制一致性带来的性能损失之外)是拥有外键允许人们编写假设存在功能性外键的代码。这绝不应该被允许。

例如,我看到人们编写代码插入到被引用的表中,然后尝试插入到引用表中而不验证第一次插入是否成功。如果稍后删除外键,则会导致数据库不一致。

您也无法选择在更新或删除时假设特定行为。无论是否存在外键,您仍然需要编写代码来执行您想要的操作。如果您假设删除是级联的,而实际上它们不是级联的,那么您的删除将失败。如果您假设对引用列的更新被传播到引用行而不是引用行,那么您的更新将失败。出于编写代码的目的,您可能还没有这些功能。

如果打开了这些功能,那么您的代码无论如何都会模拟它们,并且您将失去一点性能。

所以,总结......如果你需要一个一致的数据库,外键是必不可少的。永远不应假定外键在您编写的代码中存在或起作用。

于 2008-09-17T16:23:39.493 回答
1

The argument I have heard is that the front-end should have these business rules. Foreign keys "add unnecessary overhead" when you shouldn't be allowing any insertions that break your constraints in the first place. Do I agree with this? No, but that is what I have always heard.

EDIT: My guess is he was referring to foreign key constraints, not foreign keys as a concept.

于 2008-09-17T13:32:07.610 回答
1

对我来说,如果你想遵循ACID标准,拥有外键以确保引用完整性至关重要。

于 2008-09-17T14:13:02.177 回答
1

跨应用程序生命周期的可维护性和稳定性如何?大多数数据的生命周期都比使用它的应用程序长。关系和数据完整性太重要了,不能寄希望于下一个开发团队在应用程序代码中正确处理。如果您没有使用不尊重自然关系的脏数据的数据库,您会的。数据完整性的重要性将变得非常清楚。

于 2008-09-17T16:08:21.027 回答
1

我回应了 Dmitriy 的回答——说得很好。

对于那些担心 FK 经常带来的性能开销的人,有一种方法(在 Oracle 中)可以获得 FK 约束的查询优化器优势,而无需在插入、删除或更新期间进行约束验证的成本开销。即创建具有 RELY DISABLE NOVALIDATE 属性的 FK 约束。这意味着查询优化器假定在构建查询时已强制执行约束,而数据库实际上并未强制执行约束。当您使用这样的 FK 约束填充表时,您必须非常小心地承担责任,以确保您的 FK 列中没有违反约束的数据,就好像您这样做一样可能会从涉及此 FK 约束所在的表的查询中获得不可靠的结果。

我通常在我的数据集市模式中的某些表上使用此策略,而不是在我的集成暂存模式中。我确保我从中复制数据的表已经强制执行相同的约束,或者 ETL 例程强制执行约束。

于 2008-09-17T16:58:36.727 回答
1

我必须对这里的大部分评论置之不理,外键是确保您拥有完整数据的必要项目。ON DELETE 和 ON UPDATE 的不同选项将允许您绕过人们在此处提到的有关其使用的一些“跌倒”。

我发现在我所有项目的 99% 中,我都会使用 FK 来强制执行数据的完整性,但是,在极少数情况下,我的客户必须保留他们的旧数据,不管它有多糟糕......但是后来我花了很多时间编写代码,无论如何只获取有效数据,所以它变得毫无意义。

于 2008-09-17T14:17:50.763 回答
1

许多在这里回答的人都过于关注通过引用约束实现的引用完整性的重要性。在具有参照完整性的大型数据库上工作表现不佳。Oracle 在级联删除方面似乎特别糟糕。我的经验法则是应用程序永远不应该直接更新数据库,而应该通过存储过程。这将代码库保留在数据库中,并意味着数据库保持其完整性。

在许多应用程序可能正在访问数据库的情况下,由于参照完整性约束确实会出现问题,但这取决于控制。

还有一个更广泛的问题,应用程序开发人员可能有非常不同的需求,而数据库开发人员可能不一定那么熟悉。

于 2013-03-26T17:55:27.330 回答
0

FK 可能会给您带来问题的一种情况是,当您拥有引用该键的历史数据(在查找表中)时,即使您不再希望该键可用。
显然,解决方案是预先设计更好的东西,但我在这里考虑的是现实世界的情况,你并不总是可以控制完整的解决方案。
例如:也许您有一个customer_type列出不同类型客户的查找表 - 假设您需要删除某个客户类型,但是(由于业务限制)无法更新客户端软件,并且没有人设想这种情况在开发软件时,它是某个其他表中的外键这一事实可能会阻止您删除该行,即使您知道引用它的历史数据是不相关的。
在被这个烧了几次之后,你可能会远离关系的 db 强制。
(我并不是说这很好 - 只是给出一个你可能决定避免 FK 和 db 约束的理由)

于 2008-09-17T13:55:18.430 回答
0

我会回应 Dmitriy 所说的话,但要补充一点。

我在一个批量计费系统上工作,该系统需要在 30 多个表上插入大量行。我们不允许执行数据泵 (Oracle),因此我们必须执行批量插入。这些表上有外键,但我们已经确保它们不会破坏任何关系。

在插入之前,我们禁用外键约束,这样 Oracle 就不会永远进行插入。插入成功后,我们重新启用约束。

PS:在具有许多外键和单个记录的子行数据的大型数据库中,有时外键可能不好,您可能希望禁止级联删除。对于我们在计费系统中的我们来说,如果我们进行级联删除会花费太长时间并且对数据库过于繁重,因此我们只需在主驱动程序(父)表上使用字段将记录标记为坏记录。

于 2008-09-17T16:08:22.633 回答
0

我也听说过这个论点——那些忘记在外键上放置索引然后抱怨某些操作很慢的人(因为约束检查可以利用任何索引)。所以总结一下:没有充分的理由不使用外键。所有现代数据库都支持级联删除,所以...

于 2008-09-17T13:38:46.923 回答
0

在我从事的一个项目中,通常存在隐式而不是显式的关系,因此可以在同一列上连接多个表。

取下表

地址

  • 地址 ID (PK)
  • 实体 ID
  • 实体类型
  • 城市
  • 状态
  • 国家
  • ETC..

EntityType 的可能值可能是 Employee、Company、Customer,而 EntityId 指的是您感兴趣的任何表的主键。

我真的不认为这是做事的最佳方式,但它适用于这个项目。

于 2012-08-22T22:50:16.207 回答
0

像许多事情一样,这是一种权衡。这是您要在哪里进行工作以验证数据完整性的问题:

(1)使用外键(单点配置表,功能已经实现,测试,证明可以工作)

(2) 将其留给数据库的用户(可能有多个用户/应用程序更新同一个表,这意味着更多潜在的故障点并增加了测试的复杂性)。

数据库执行 (2) 更高效,更易于维护且风险更小 (1)。

于 2008-09-18T04:17:27.513 回答
0

在 DB2 中,如果使用 MQT(物化查询表),优化器需要外键约束才能为任何给定查询选择正确的计划。由于它们包含基数信息,优化器大量使用元数据来使用 MQT。

于 2013-12-04T18:47:38.713 回答
0

数据结构设计的一个好的原则是确保表或对象的每个属性都受到易于理解的约束。这很重要,因为如果您或您的程序可以依赖数据库中的有效数据,那么您就不太可能出现由错误数据引起的程序缺陷。您还花费更少的时间编写代码来处理错误情况,并且您更有可能预先编写错误处理代码。

在许多情况下,这些约束可以在编译时定义,在这种情况下,您可以编写一个过滤器以确保属性始终在范围内,否则保存属性的尝试会失败。

但是,在许多情况下,这些约束可能会在运行时发生变化。例如,您可能有一个“汽车”表,它具有“颜色”作为属性,该属性最初采用“红色”、“绿色”和“蓝色”等值。在程序执行期间,可以将有效颜色添加到该初始列表中,并且添加的新“汽车”可以采用最新颜色列表中的任何颜色。此外,您通常希望这个更新的颜色列表在程序重新启动后仍然存在。

要回答您的问题,事实证明,如果您需要可以在运行时更改的数据约束,并且这些更改必须在程序重新启动后仍然存在,那么外键是解决该问题的最简单和最简洁的解决方案。开发成本是添加一个表(例如“colors”、对“cars”表的外键约束和索引),运行时成本是针对最新颜色的额外表查找来验证数据,并且这种运行时成本通常通过索引和缓存来减轻。

如果您不使用外键来满足这些要求,则必须编写软件来管理列表,查找有效条目,将其保存到磁盘,如果列表很大,则有效地构建数据,确保对列表的任何更新都不会损坏列表文件,在有多个读取器和/或写入器的情况下提供对列表的串行访问,等等。ie 你需要实现很多 RDBMS 功能。

于 2010-06-11T19:27:26.040 回答
0

我们经常收到带有 FK 约束的错误无法添加 或更新子行:外键约束失败 假设有两个表 inventory_source 和 contract_lines,我们从 inventory_source 引用contract_lines 中的 inventory_source_id并假设我们想从 inventory_source 删除记录并且该记录已经存在于 contract_lines 中,或者我们想从 Base 表中删除 PK 列,我们会收到 FK 约束错误,我们可以使用下面记下的步骤来避免它。

CREATE TABLE inventory_source (
inventory_source_id int(11) NOT NULL AUTO_INCREMENT,
display_name varchar(40) NOT NULL,
state_id int(11) NOT NULL,
PRIMARY KEY (inventory_source_id),
KEY state_id (state_id),
CONSTRAINT ba_inventory_source_state_fk FOREIGN KEY (state_id) REFERENCES   ba_state (state_id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

CREATE TABLE contract_lines(
contract_line_id int(11) NOT NULL AUTO_INCREMENT,
inventory_source_id int(11) NULL ,
PRIMARY KEY (contract_line_id),
UNIQUE KEY contract_line_id (contract_line_id),
KEY AI_contract_line_id (contract_line_id),
KEY contract_lines_inventory_source_fk (inventory_source_id),
CONSTRAINT contract_lines_inventory_source_fk FOREIGN KEY       (inventory_source_id) REFERENCES ba_inventory_source (inventory_source_id)
) ENGINE=InnoDB AUTO_INCREMENT=135 DEFAULT CHARSET=utf8 ;

我们可以通过以下步骤克服它:-

  1. 从inventory_source 中删除或更新行将自动删除或更新contract_lines 表中的匹配行,这称为级联删除或更新。
  2. 另一种方法是在inventory_source 表中删除对应的记录时,将contract_lines 表中的列即inventory_source_id 设置为NULL。
  3. 我们可以限制父表的删除或更新,换句话说,可以拒绝对inventory_source 表的删除或更新操作。
  4. 如果引用的表中存在相关的外键值,则不允许尝试删除或更新主键值。
于 2015-04-15T07:38:38.127 回答
0

Wowowo...
到处都有答案。其实这是我遇到过的最复杂的话题。我在需要时使用 FK,但在生产环境中我很少使用它们。

以下是我很少使用 FKS 的原因:

1. 大多数时候我在小型服务器上处理大量数据以提高性能,我需要删除 FK。因为当您有 FK 并且您创建、更新或删除 RDBMS 时,首先检查是否没有违反约束以及是否有可能是致命的巨大数据库

2. 有时我需要从其他地方导入数据,因为我不是太确定它们的结构有多好,我只是放弃了 FK。

3. 如果您正在处理多个 DB 并且在另一个 DB 中具有引用键将不会顺利(目前),直到您删除 FK(跨数据库关系)
4. 当您编写一个应用程序时也是如此将坐在任何 RDBMS 上,或者您希望您的数据库在任何 RDBMS 系统中导出和导入,在这种情况下,每个特定的 RDBMS 系统都有自己处理 FK 的方式,您可能不得不放弃使用 FK。

5. 如果您使用 RDBMS 平台 (ORM),您知道其中一些根据他们提供的解决方案和技术性提供自己的映射,并且您不关心创建表及其 FK。

6. 在最后一点之前,将是处理具有 FK 的 DB 的知识以及编写无需 FK 7 即可完成所有工作的应用程序的知识。最后,正如我开始所说的,这一切都取决于您的场景,以防万一知识不是障碍。您将始终希望尽最大努力做到最好!


谢谢大家!

于 2019-08-08T11:59:57.887 回答
-1

I always thought it was lazy not to use them. I was taught it should always be done. But then, I didnt listen to Joel's discussion. He may have had a good reason, I don't know.

于 2008-09-17T13:29:58.413 回答
-9

I can see a few reasons to use foreign keys (Orphaned rows, as someone mentioned, are annoying) but I never use them either. With a relatively sane DB schema, I don't think they are 100% needed. Constraints are good, but enforcing them via software is a better method, I think.

Alex

于 2008-09-17T13:32:11.183 回答