当前位置:  开发笔记 > 编程语言 > 正文

外键有什么问题?

如何解决《外键有什么问题?》经验,为你挑选了10个好方法。

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

人们有一些坚实的理由为什么(避免与Stack Overflow原则一致的讨论)?

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



1> SquareCog..:

使用外键的原因:

你不会得到孤儿行

你可以得到很好的"删除级联"行为,自动清理表

了解数据库中表之间的关系有助于优化器计划您的查询以实现最高效的执行,因为它能够更好地估计连接基数.

FK对数据库中最重要的统计数据给出了相当大的暗示,这反过来又会带来更好的性能

它们支持各种自动生成的支持 - ORM可以生成自己,可视化工具将能够为您创建漂亮的模式布局等.

项目的新手将更快地进入事物流,因为其他隐式关系是明确记录的

不使用外键的原因:

你正在使每个CRUD操作的DB工作更多,因为它必须检查FK一致性.如果你有很多流失,这可能是一个很大的代价

通过强制执行关系,FK指定了必须添加/删除内容的顺序,这可能导致数据库拒绝执行您想要的操作.(当然,在这种情况下,你要做的是创建一个孤立行,这通常不是一件好事).当您进行大批量更新时,这是非常痛苦的,并且您在另一个表之前加载一个表,第二个表创建一致状态(但如果第二个加载可能失败并且您的数据库现在不一致?).

有时你事先知道你的数据会变脏,你接受了,并且你希望数据库接受它

你只是在偷懒:-)

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


好清单!DBM不会检查CRUD的"R"部分的一致性,所以我会把那部分拿出来.此外,它可能是一个洗,因为在你的应用程序中你做了同样的事情DBMS:你会检查并确保父ID在CRD之前是有效的,这实际上比让DBM做的慢!
在我看来,使用外键FAR的好处超过了不使用外键的好处.
确切地说 - 它应该是DB的工作,因为它是唯一可以保证面对多个并发客户端的事务性的工作.
如果有人在您插入孩子时删除了父母,该怎么办?现在,当我提交"添加评论"时 - 如果您已经删除了答案,此评论现在是一个孤儿.FK会阻止它.另外,我可以将parentID更改为我想要的任何内容.有人需要检查.:)
+1优秀的答案 - 不使用FK约束的第二个原因可以被认为是"使得更难以打破一致性",这实际上听起来像一个*好*的东西!
我不喜欢FK.对于其他评论中提到的备份和自由,但出于许多其他原因.我的首要原因是,我将其用于恢复目的.就像说我有几个表与客户打交道(通过各种各样的ID).如果我从主客户端表中删除记录,它将有效删除对该客户端记录的所有访问权限(应用程序不知道它存在)这使我可以通过重新创建单个记录(而不是数百个)来非常轻松地恢复错误.我有后台进程,最终将删除数据(和备份).我更喜欢app层上的API层
唯一要注意的是像我们使用的大型系统,我们从不配置级联删除.我们的删除是通过在父母之前删除孩子的维护脚本完成的.创建批处理任务确实需要一些时间,但是对于数据库的完整性来说是值得的.我总是使用FK进行优化和数据完整性检查.但有时候我们的DBA会出现批量删除/维护问题,因为它可能会给他们带来不便.

2> 小智..:

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

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

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


我将使用蒸馏的"外键就像刷牙一样:继续,不用它,但是当你微笑的时候要小心"
我个人发现RDBMS的原理比口腔卫生更简单,更明确

3> AlexCuse..:

引用Joe Celko:

"就像26号皮带一样,只是因为你的意思并不代表你应该这么做!"

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

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


我真的不会让那些在他们的数据库中没有FK的人.我最后一次与没有它的人合作,他说"不,我们在申请中强制执行." 除了我对所有客户数据库进行了调查,发现他们中的大多数都有孤儿......
由于表之间的_relationships_(不是每种数据库在实体之间都有某种关系!),所以不将数据库称为_relational_,但是用数学术语来说,因为表本身是_relations_。请参阅[Wikipedia](https://en.wikipedia.org/wiki/Relational_database#Relations_or_tables)。

4> Galwegian..:

外键对于任何关系数据库模型都是必不可少的.


模型,是的.实施,不是必要的,只是可能有用.
对不起,但是应用程序开发人员更广泛地使用对象数据库管理系统(又名NoSQL数据库!)的主要原因是因为对RDBMS的投资.大多数情况下,数据库(不是数据库管理系统)是通常涉及分布式缓存的中间层对象模型.这是无论如何必须发生删除级联,所有权和变更同步的地方.RDBMS主要用于此对象模型的持久性,通常是经过艰苦的,实际上毫无价值的ORM练习之后.关系模型大部分时间都没有必要!
不,外键不强制表示"关系"

5> Ant..:

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

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

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


很好的见解.我认为数据对于实际使用的每个应用程序都很重要.唯一不同的是腐败数据的后果.它们适用于您的应用程序......

6> Nathan Long..:
外键使自动化测试变得复杂

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

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

现在,如果没有在与测试无关的四个表中设置数据,数据库将不允许您运行测试.

至少有两种可能的观点:

"这是一件好事:你的测试应该是现实的,那些数据限制将存在于生产中."

"这是一件坏事:你应该能够在不涉及其他部分的情况下对系统进行单元测试.你可以为系统整体添加集成测试."

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


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


还有DBMS允许约束到*deferred*,以便只在提交整个事务时检查它们,因此insert,update,delete的顺序无关紧要
您的数据库甚至不应该参与您的单元测试,您应该嘲笑它们.在集成测试中,他们会参与,但由于外键导致的任何问题都是您的用户也会遇到的问题,除非您修复它.
如果要从业务层测试更新,则开发环境应具有FK。更新记录时,应具有成功更新所需的列值。否则,恕我直言,您的测试无效。

7> Powerlord..:

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

重要的是要记住,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.

默认值似乎取决于您使用的是哪个sql server.



8> Ed Guiness..:

@imphasing - 这正是那种导致维护噩梦的心态.

为什么哦,为什么你会忽略声明性参照完整性,其中数据可以保证至少是一致的,有利于所谓的"软件执行",这是一种最好的弱预防措施.



9> Kent Fredric..:

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

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

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


在没有备份的情况下删除生产中的行不是有效参数.如果你不理解它们,你应该考虑学习它而不是省略它.
@Guillaume我认为他的答案有点讽刺,不能从字面上理解:如果你不理解它们,那么就不要使用它们.但是你当然应该*理解并使用它们.

10> Matt Rogish..:

没有充分的理由使用它们......除非孤立的行对你来说不是什么大问题.


为什么孤立行很重要?
多线程怎么样?在某些情况下,它们可能会导致多线程的噩梦.在具有多个线程的复杂应用程序中编写可能遇到需要相互引用的对象的数据库时,最好控制业务逻辑中的参照完整性 - 特别是如果表格之后将变为静态.
推荐阅读
ar_wen2402851455
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有