外键有什么问题?

时间:2008-09-17 13:25:55

标签: database database-design foreign-keys referential-integrity data-integrity

我记得Joel Spolskypodcast 014中提到他几乎没用过外键(如果我没记错的话)。但是,对我而言,在整个数据库中避免重复和后续数据完整性问题似乎非常重要。

人们是否有一些可靠的理由(为避免与Stack Overflow原则一起讨论)?

修改: "I've yet to have a reason to create a foreign key, so this might be my first reason to actually set up one."

38 个答案:

答案 0 :(得分:339)

使用外键的原因:

  • 你不会得到孤儿行
  • 你可以获得“删除级联”行为,自动清理表格
  • 了解数据库中表之间的关系有助于Optimizer计划您的查询以实现最高效的执行,因为它能够更好地估计连接基数。
  • FK提供了一个相当大的提示,说明在数据库上收集哪些统计数据最重要,这反过来会带来更好的性能
  • 它们支持各种自动生成的支持 - ORM可以自行生成,可视化工具将能够为您创建漂亮的模式布局等。
  • 项目的新手将更快地进入事物流,因为明确记录了隐含的关系

不使用外键的原因:

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

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

答案 1 :(得分:78)

这是一个培养问题。如果你在教育或职业生涯的某个地方花时间喂养和照顾数据库(或者与有才能的人一起密切合作),那么实体和关系的基本原则在你的思维过程中根深蒂固。其中的基础是如何/何时/为什么在数据库中指定密钥(主要,外部和备用)。这是第二天性。

但是,如果您在过去与RDBMS相关的工作中没有那么彻底或积极的经验,那么您可能没有接触到这些信息。或许你的过去包括沉浸在一个大声反数据库的环境中(例如,“那些DBA是白痴 - 我们很少,我们选择了几个java / c#代码甩卖者将节省一天”),在这种情况下你可能会强烈反对一些dweeb的神秘唠叨告诉你,如果你只是倾听,FK(以及他们可以暗示的限制)真的很重要。

大多数人都是在他们还是小孩的时候教过刷牙很重要。你可以没有它吗?当然,但是如果你在每顿饭后刷过,那么在某个地方你可以获得的牙齿比你可以拥有的牙齿少。如果妈妈和爸爸有足够的责任来涵盖数据库设计和口腔卫生,我们就不会进行这种对话。 : - )

答案 2 :(得分:52)

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

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

答案 3 :(得分:39)

对于任何关系数据库模型,外键都是必需

答案 4 :(得分:29)

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

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

如果您的数据很重要,那么请使用外键,创建一套存储过程来与数据交互,并创建最难的数据库。如果您的数据不重要,为什么要开始使用数据库?

答案 5 :(得分:18)

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


外键使自动化测试复杂化

假设您正在使用外键。您正在编写一个自动化测试,上面写着“当我更新金融帐户时,它应该保存交易记录。”在此测试中,您只关注两个表:accountstransactions

但是,accountscontracts的外键,而contracts的fk为clientsclients的fk为cities }},cities的fk为states

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

至少有两种可能的观点:

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

也可以在运行测试时暂时关闭外键检查。 MySQL,至少是supports this

答案 6 :(得分:14)

“他们可以删除记录更加繁琐 - 你不能删除”主“记录,其他表中有外键会违反该约束的记录。”

重要的是要记住,SQL标准定义了删除或更新外键时所采取的操作。 我所知道的是:

  • ON DELETE RESTRICT - 防止删除其他表中包含此列中键的所有行。这就是Ken Ray所描述的内容。
  • ON DELETE CASCADE - 如果删除了另一个表中的某一行,请删除此表中引用它的所有行。
  • ON DELETE SET DEFAULT - 如果删除了另一个表中的某一行,请将引用它的任何外键设置为该列的默认值。
  • ON DELETE SET NULL - 如果删除了另一个表中的一行,请将此表中引用它的任何外键设置为null。
  • ON DELETE NO ACTION - 此外键仅标记它是外键;即用于OR映射器。

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

默认值似乎取决于您正在使用的服务器。

答案 7 :(得分:14)

@imphasing - 这正是造成维护噩梦的那种心态。

为什么哦,为什么你会忽略声明性引用完整性,其中数据可以保证至少是一致的,有利于所谓的“软件实施”,这是一种最好的弱预防措施。

答案 8 :(得分:12)

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

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

另外,相反,当你需要移除某些东西时,如果设计不当,约束会导致各种阻止你的锁。

答案 9 :(得分:11)

没有良好原因使用它们......除非孤立的行对我来说不是什么大问题。

答案 10 :(得分:5)

更大的问题是:你会带着眼罩开车吗?如果你开发一个没有参考约束的系统,那就是这样。请记住,业务需求变化,应用程序设计更改,代码更改中的相应逻辑假设,逻辑本身可以重构,等等。一般而言,数据库中的约束在当前逻辑假设下实施,对于特定的逻辑断言和假设集似乎是正确的。

通过应用程序的生命周期,参考和数据检查可以限制通过应用程序收集警察数据,尤其是在新要求推动逻辑应用程序更改时。

对于此列表的主题 - 外键本身并不“提高性能”,也不会从实时事务处理系统的角度显着“降低性能”。但是,在高容量“批量”系统中存在约束检查的聚合成本。所以,这是差异,实时与批量交易过程;批处理 - 通过约束检查产生的经过处理的批次处理后的成本受到影响,性能受到影响。

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

QUERY PERFORMANCE - 如果表连接在外键上,请认识到外键列不是INDEXED(尽管各个主键按定义编制索引)。通过索引外键,就此而言,通过索引任何键,并在索引上连接表有助于提高性能,而不是通过加入具有外键约束的非索引键。

更改主题,如果数据库只是支持网站显示/呈现内容/等并记录点击次数,那么对所有表格具有完全约束的数据库就会因此而被杀死。想一想。大多数网站甚至不使用数据库。对于类似的要求,只是记录数据而不是按照说法引用数据,请使用没有约束的内存数据库。这并不意味着没有数据模型,是逻辑模型,而是没有物理数据模型。

答案 11 :(得分:3)

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

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

答案 12 :(得分:3)

"在添加记录之前,检查另一个表中是否存在相应的记录"是商业逻辑。

以下是您不希望在数据库中出现这种情况的一些原因:

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

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

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

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

答案 13 :(得分:3)

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

最好避免使用FK,但风险必须由程序员处理。

答案 14 :(得分:2)

我只知道Oracle数据库,没有其他数据库,我可以说外键对于维护数据完整性至关重要。在插入数据之前,需要进行数据结构,并使其正确。完成后 - 因此创建了所有主要和外键 - 工作就完成了!

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

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

缺点?是的,一点没错 !因为在插入时,将会发生更多的检查。但是,如果数据完整性比性能更重要,那么这是一个明智的选择。 Oracle上的性能问题与PK和FK的索引更相关。

答案 15 :(得分:2)

我同意之前的答案,因为它们对于保持数据一致性很有用。然而,几个星期前有一个interesting post by Jeff Atwood讨论了规范化和一致数据的优缺点。

简而言之,在处理大量数据时,非规范化数据库可以更快;并且您可能不关心精确的一致性,具体取决于应用程序,但它会强制您在处理数据时更加小心,因为数据库不会。

答案 16 :(得分:1)

他们可以使删除记录更加繁琐 - 你不能删除其他表中有外键会违反该约束的记录的“主”记录。您可以使用触发器进行级联删除。

如果您不明智地选择了主键,那么更改该值会变得更加复杂。例如,如果我将“客户”表的PK作为人名,并在“订单”表中将该密钥设为FK,“如果客户想要更改其名称,那么这是一个皇家的痛苦......但这只是伪劣的数据库设计。

我相信使用fireign键的优势超过了任何所谓的缺点。

答案 17 :(得分:1)

许多在这里回答的人都太依赖于通过参照约束实现参照完整性的重要性。使用引用完整性处理大型数据库效果不佳。 Oracle在级联删除方面似乎特别糟糕。我的经验法则是应用程序不应该直接更新数据库,而应该通过存储过程。这使代码库保持在数据库中,并意味着数据库保持其完整性。

在许多应用程序可能正在访问数据库的情况下,由于引用完整性约束而出现问题,但这归结为控件。

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

答案 18 :(得分:1)

我听到的论点是前端应该有这些业务规则。当你不应该允许任何插入破坏你的约束时,外键“增加了不必要的开销”。我同意这个吗?不,但这是我一直听到的。

编辑:我的猜测是他指的是外键约束,而不是外键作为概念。

答案 19 :(得分:1)

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

但这是另一个非常好的现实生活理由,根本不使用外键:

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

如果您正在使用能够连接到许多不同数据库系统的Entity Framework,您可能还需要支持"开源免费"无服务器数据库。并非所有这些数据库都支持您的外键规则(更新,删除行......)。

这会导致不同的问题:

1。)创建或更新数据库结构时,可能会遇到错误。也许只会出现无提示错误,因为数据库系统会忽略您的外键。

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

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

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

答案 20 :(得分:1)

我回应德米特里的答案 - 非常好。

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

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

答案 21 :(得分:1)

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

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

您也无法选择在更新或删除时采取特定行为。无论是否存在外键,您仍然需要编写代码来执行您想要的操作。如果您认为删除不是级联,则删除将失败。如果您假定引用列的更新未引用到引用行,则更新将失败。出于编写代码的目的,您可能没有这些功能。

如果启用了这些功能,那么您的代码无论如何都会模仿它们,您将失去一点性能。

因此,摘要....如果您需要一致的数据库,外键是必不可少的。永远不要假定外键在您编写的代码中存在或起作用。

答案 22 :(得分:1)

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

答案 23 :(得分:1)

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

答案 24 :(得分:1)

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

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

答案 25 :(得分:1)

对我而言,如果您想遵循ACID标准,那么使用外键确保参照完整性至关重要。

答案 26 :(得分:1)

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

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

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

换句话说,他们可以使用显式声明(DRI)加入表格,但选择不

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

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

我认为,这是在关系数据库中没有外键约束的主要好处。这使得开发更容易,至少从恶魔般的关注角度来看。

答案 27 :(得分:1)

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

答案 28 :(得分:0)

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

这是我很少使用Fks的原因:

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

 2.有时我需要从其他地方导入数据,并且由于我不太确定它们的结构如何,我只需要删除FK。

 3.如果您要处理多个数据库,并且在另一个数据库中拥有引用密钥(直到现在)将无法正常进行(直到现在),除非您删除FK(跨数据库关系)
 4.当您编写一个可以放在任何RDBMS上的应用程序,或者您希望在任何RDBMS系统中导出和导入数据库时​​,也是这种情况,在这种情况下,每个特定的RDBMS系统都有自己的处理FK的方式,可能不得不放弃使用FK。

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

 6.在最后一点之前,将要学习处理具有FK的DB的知识,以及编写无需FK即可完成所有工作的应用程序的知识  7.最后,当我开始说这一切都取决于您的情况时,以防知识不是障碍。您将永远想尽自己所能中的最好方法!


谢谢大家!

答案 29 :(得分:0)

我一直认为不使用它们是懒惰的。我被教导应该永远这样做。但后来,我没有听过乔尔的讨论。他可能有充分的理由,我不知道。

答案 30 :(得分:0)

Q 我们经常收到 FK约束的错误 无法添加或更新子行:外键约束失败 假设有两个表inventory_source和contract_lines,我们在inventory_source 的contract_lines中引用 inventory_source_id,并假设我们要从inventory_source中删除记录,并且记录已存在于contract_lines中,或者我们要删除PK列从Base表中,我们得到了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. 如果引用的表中存在相关的外键值,则不允许继续尝试删除或更新主键值。

答案 31 :(得分:0)

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

答案 32 :(得分:0)

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

答案 33 :(得分:0)

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

参见下表

<强>地址

  • AddressId(PK)
  • ENTITYID
  • 的EntityType
  • 国家
  • 等。

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

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

答案 34 :(得分:0)

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

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

但是,在许多情况下,这些约束可能会在运行时更改。例如,您可能有一个“汽车”表,其中“颜色”作为属性,最初采用“红色”,“绿色”和“蓝色”等值。在程序执行期间可以向该初始列表添加有效颜色,并且添加的新“汽车”可以采用最新颜色列表中的任何颜色。此外,您通常希望此更新的颜色列表能够在程序重启后继续使用。

要回答您的问题,事实证明,如果您要求数据约束可以在运行时更改,并且这些更改必须在程序重启后继续存在,则外键是解决问题的最简单,最简洁的解决方案。开发成本是添加一个表(例如“颜色”,“汽车”表的外键约束和索引),运行时成本是最新颜色的额外表查找验证数据,通常通过索引和缓存来减少此运行时成本。

如果您不使用外键来满足这些要求,则必须编写软件来管理列表,查看有效条目,将其保存到磁盘,如果列表很大则有效地构建数据,确保对列表进行任何更新不要破坏列表文件,提供对列表的串行访问,以防有多个读者和/或编写者,等等。即您需要实现许多RDBMS功能。

答案 35 :(得分:0)

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

(1)使用外键(单点配置表,功能已经实现,测试,证明有效)

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

数据库更有效(2),更容易维护,风险更低(1)。

答案 36 :(得分:0)

我会回应德米特里说的话,但是还要补充一点。

我在一个需要在30多个表上插入大量行的批量计费系统。我们不允许使用数据泵(Oracle),所以我们不得不进行批量插入。这些表格上有外键,但我们已经确保它们没有破坏任何关系。

在插入之前,我们禁用外键约束,以便Oracle不会永远执行插入操作。插入成功后,我们重新启用约束。

PS:在一个包含许多外键和单行记录的子行数据的大型数据库中,有时外键可能不好,您可能想要禁止级联删除。对于我们的计费系统,如果我们进行级联删除,则需要太长时间并且对数据库过于沉重,因此我们只是将记录标记为主驱动程序(父)表上的字段。

答案 37 :(得分:-8)

我可以看到使用外键的几个原因(孤立的行,如有人提到的,很烦人),但我也从不使用它们。使用相对理智的数据库架构,我不认为它们是100%需要的。约束是好的,但我认为通过软件强制执行它们是一种更好的方法。

Alex