ljs*_*ljs 250 database database-design referential-integrity foreign-keys data-integrity
我记得听过Joel Spolsky在播客014中提到他几乎没用过外键(如果我没记错的话).但是,对我而言,在整个数据库中避免重复和后续数据完整性问题似乎非常重要.
人们有一些坚实的理由为什么(避免与Stack Overflow原则一致的讨论)?
Squ*_*Cog 343
使用外键的原因:
不使用外键的原因:
我认为(我不确定!)大多数已建立的数据库提供了一种指定未强制执行的外键的方法,并且只是一些元数据.由于非执法部门消除了不使用FK的所有理由,如果第二部分中的任何原因适用,您应该走这条路线.
小智 80
这是一个培养问题.如果你在教育或职业生涯的某个地方花时间喂养和照顾数据库(或者与有才能的人一起密切合作),那么实体和关系的基本原则在你的思维过程中根深蒂固.其中的基础是如何/何时/为什么在数据库中指定密钥(主要,外部和备用).这是第二天性.
但是,如果您在过去与RDBMS相关的工作中没有那么彻底或积极的经验,那么您可能没有接触到这些信息.或者也许你的过去包括沉浸在一个大声反数据库的环境中(例如,"那些DBA是白痴 - 我们很少,我们选择了几个java/c#代码甩尾者会挽救这一天"),在这种情况下你可能会强烈反对对于一些dweeb的神秘唠叨告诉你,如果你只是倾听,FK(以及他们可以暗示的限制)真的很重要.
大多数人都是在他们还是小孩的时候被教过,刷牙很重要.你可以没有它吗?当然,但是如果你在每顿饭后刷过,那么在某个地方你可以获得的牙齿比你可以拥有的牙齿少.如果妈妈和爸爸有足够的责任来涵盖数据库设计和口腔卫生,我们就不会进行这种对话.:-)
Ale*_*use 52
引用Joe Celko:
"就像26号皮带一样,只是因为你的意思并不代表你应该这么做!"
我确信有很多应用程序可以让你逃脱它,但这不是最好的主意.您不能总是指望您的应用程序正确管理您的数据库,坦率地管理数据库不应该是您的应用程序非常关注.
如果您使用的是关系数据库,那么您似乎应该在其中定义一些关系.不幸的是,这种态度(你不需要外键)似乎被许多应用程序开发人员所接受,他们宁愿不被数据完整性等愚蠢的事情所困扰(但需要因为他们的公司没有专门的数据库开发人员).通常在这些类型的数据库中,你很幸运只有主键;)
Gal*_*ian 41
外键对于任何关系数据库模型都是必不可少的.
Ant*_*Ant 29
我总是使用它们,但后来我为金融系统制作数据库.数据库是应用程序的关键部分.如果财务数据库中的数据不完全准确,那么您在代码/前端设计中花费了多少精力并不重要.你只是在浪费时间.
还有一个事实是,多个系统通常需要直接与数据库接口 - 从刚读取数据的其他系统(Crystal Reports)到插入数据的系统(不一定使用我设计的API;它可能由一个刚刚发现VBScript且具有SQL框SA密码的愚蠢的经理.如果数据库不像它可能的那样白痴,那么再见数据库.
如果您的数据很重要,那么请使用外键,创建一组存储过程来与数据交互,并创建最难的数据库.如果您的数据不重要,为什么要开始使用数据库?
Nat*_*ong 20
假设您正在使用外键.您正在编写一个自动化测试,上面写着"当我更新金融帐户时,它应该保存交易记录." 在这个测试中,你只关心两个表:accounts
和transactions
.
但是,accounts
有一个外键contracts
,并且contracts
有一个fk clients
,并且clients
有一个fk cities
,并且cities
有一个fk到states
.
现在,如果没有在与测试无关的四个表中设置数据,数据库将不允许您运行测试.
至少有两种可能的观点:
也可以在运行测试时暂时关闭外键检查.MySQL至少支持这一点.
更新:我现在总是使用外键.我对"他们复杂测试"的反对意见的回答是"编写你的单元测试,以便他们根本不需要数据库.任何使用数据库的测试都应该正确使用它,包括外键.如果设置很痛苦,找到一种不太痛苦的方法进行设置."
Pow*_*ord 15
"他们可以删除记录更加繁琐 - 你不能删除"主"记录,其他表中有外键会违反该约束的记录."
重要的是要记住,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.
Ed *_*ess 14
@imphasing - 这正是那种导致维护噩梦的心态.
为什么哦,为什么你会忽略声明性参照完整性,其中数据可以保证至少是一致的,有利于所谓的"软件执行",这是一种最好的弱预防措施.
Ken*_*ric 12
有一个很好的理由不使用它们: 如果你不理解它们的作用或如何使用它们.
在错误的情况下,外键约束可能导致事故的瀑布复制.如果有人删除了错误的记录,撤消它可能会成为一项巨大的任务.
而且,相反,当你需要移除某些东西时,如果设计不当,约束会导致各种阻止你的锁.
Mat*_*ish 11
没有充分的理由不使用它们......除非孤立的行对你来说不是什么大问题.
小智 7
根据我的经验,最好避免在数据库关键应用程序中使用 FK。我不会不同意这里的人说 FK 是一种很好的做法,但在数据库很大且每秒有大量 CRUD 操作的情况下它不实用。我可以不透露姓名地分享……最大的投资银行之一的数据库中没有一个 FK。这些约束由程序员在创建涉及数据库的应用程序时处理。基本原因是,当完成新的 CRUD 时,它必须影响多个表并验证每个插入/更新,尽管这对于影响单行的查询来说不是一个大问题,但在处理时它确实会产生巨大的延迟批处理是任何大银行都必须执行的日常任务。
最好避免 FK,但其风险必须由程序员来处理。
“在添加记录之前,检查另一个表中是否存在相应的记录”是业务逻辑。
以下是您不希望在数据库中使用它的一些原因:
如果业务规则发生变化,您必须更改数据库。在很多情况下,数据库需要重新创建索引,这在大表上很慢。(更改规则包括:允许访客发布消息或允许用户在发表评论后删除其帐户等)。
更改数据库并不像通过将更改推送到生产存储库来部署软件修复那么容易。我们希望尽可能避免更改数据库结构。数据库中的业务逻辑越多,需要更改数据库(并触发重新索引)的机会就越大。
TDD。在单元测试中,您可以用数据库代替模拟并测试功能。如果您的数据库中有任何业务逻辑,则您没有进行完整的测试,需要使用数据库进行测试或在代码中复制业务逻辑以进行测试,从而复制逻辑并增加逻辑在数据库中不起作用的可能性同样的方法。
使用不同的数据源重用您的逻辑。如果数据库中没有逻辑,我的应用程序可以从数据库中的记录创建对象,从 Web 服务、json 文件或任何其他来源创建对象。我只需要换出数据映射器实现,就可以将我的所有业务逻辑与任何来源一起使用。如果数据库中有逻辑,这是不可能的,您必须在数据映射器层或业务逻辑中实现逻辑。无论哪种方式,您都需要在代码中进行这些检查。如果数据库中没有逻辑,我可以使用不同的数据库或平面文件实现将应用程序部署到不同的位置。