为什么不建议使用数据库外键

开发规范中要求:

【强制】不得使用外键与级联,一切外键概念必须在应用层解决。

原因使用数据库外键有以下缺点:


 

1.外键的性能问题

我刚写了一些,然后发现有人写的更好而且简洁,就引用吧:@mysqlops

为何说外键有性能问题:
1.数据库需要维护外键的内部管理;
2.外键等于把数据的一致性事务实现,全部交给 数据库服务器完成;
3.有了外键,当做一些涉及外键字段的增,删,更新操作之后,需要触发相关操作去检查,而不得不消耗资源;
4.外键还会因为需要请求对其他表内部加锁而容易出现死锁情况;
作者:mysqlops
链接: 大家设计数据库时使用外键吗? - 知乎
来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

总的来说物理外键是个比较“重”的实现,他会不顾性能不分轻重缓急的给你保证一致性。

2.mysql的外键设计问题

虽然很多人都不推荐你在关系型数据库使用外键。 但你更多听到的是mysql的,而不是SQLserver或者其他。比较公认的是,他的外键设计得的确不是很好,限制多功能不强大等,以innodb 为例子,包含但不限于以下几点(我认为比较严重的)

  • 所有tables必须是InnoDB型,它们不能是临时表。
  • 在引用表中,必须有一个索引,外键列以同样的顺序被列在其中作为第一列。这样一个索引如果不存在,它必须在引用表里被自动创建。
  • 不支持对外键列的索引前缀。这样的后果之一是BLOB和TEXT列不被包括在一个外键中,这是因为对这些列的索引必须总是包含一个前缀长度
  • InnoDB不对那些外键或包含NULL列的被引用键值检查外键约束

详细参考mysql的外键约束 - Johney - 博客园

印象中轮子哥

@vczh

在回答一个跟存储过程有关的问题提到过,其他数据库不建议使用存储过程那是因为他们设计的不好,银行内不都比较推荐甚至要求sqlserver使用存储过程么(你没骗我吧)。反正我以前也是用sqlserver的,我觉得是挺好的。

3.外键对拓展性的限制和影响

外键的主从关系是定的,然后你会遵守这个规矩去干活。但是计划赶不上变化,万一哪天主键所在表需要拆分了呢?需要重构了呢?万一哪天你突然发现外键表不是非得跟主表的主键挂上关系呢?就我经历过的来看,这种情况并不少见,尤其是数据库设计者水平不够高的情况下。

另一方面,数据库帮你保证级联关系,你平时写程序的时候就真的思路清晰吗?因为某些原因(比如你想要的关系数据库不支持,mysql经常),有些地方你就不能设计外键了,当有级联更新的需要时,一部分靠物理外键,一部分还得靠自己,我觉得还不如全靠代码逻辑去保证。即使你对业务理解深刻,对外键也掌握的透彻,你也不太希望老是你管一部分他管一部分吧?

再放个大招,当你需要分库分表的时候,外键就浮云了

4.逻辑外键在业界比较成熟

外键是个好东西,不使用物理外键,我们也可以约定逻辑外键(不在数据库声明FK,在程序实现上表达关联)

数据库上的策略:可以选择大多数情况下我们只更新不删除,也就是逻辑删,不再使用的历史数据定期归档来减少压力。

代码的设计和限制:对表范围的操作权限,开启事务去处理逻辑,有需要进行异步操作来提高性能的我们设计补偿机制去弥补,等等。

有人问原本在物理外键的开销,在程序上不也有开销吗。但是这样我们对优化性能的方式也灵活了,刚刚说的异步处理就是一种。视具体情况而定,如果设计的好,有时候某些“脏数据”你不是非得立刻删除他,甚至不是非得删除他。对于正确性>性能的说法,如果逻辑复杂到一定程度,物理外键一定能给你提供正确性吗?这个可以讨论讨论。



作者:justabug
链接:https://www.zhihu.com/question/39062169/answer/156096473
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。