⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 http://www.justabug.net/think-in-mysql-foreign-key/ 「justabug」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

首先贴一下知乎上的问题和回答

为什么很多mysq课程不推荐用物理外键

之前是由于有师弟跟我讨论这个问题,然后我是顺便搜了下知乎把想法也都写下,现在把他放回博客,然后进行了一下细化,依然是just a door系列,依然是为了更前面的探讨一些问题,本期topic是物理外键~let’s start with mysql

img

First of all,什么是物理外键,好吧虽然基础,但是我们不能跑偏,所以啰嗦的虫子还是喜欢把概念链接给贴上,维基百科更详细,不过这个逼就不装了,留给你们吧

Foreign-Key(w3school)

Using FOREIGN KEY Constraints(mysql官网)

原文:用外键的好处我就不多说了,既然是关系型数据库,外键的约束为我们保证了数据主从关系和产生的先后关系,级联操作为我们的update和delete带来了不少方便。但成本是有的,你要权衡你是不是想付出这些代价。成本参考以下几点:

这里我再贴个链接,先给使用外键的优点这边投一票 :外键的好处

那既然他这么好,为什么我不推荐你使用呢?我们来看个例子,然后我们根据以下的点来分析:

一、外键的性能问题

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

为何说外键有性能问题:

1.数据库需要维护外键的内部管理;

2.外键等于把数据的一致性事务实现,全部交给数据库服务器完成;

3.有了外键,当做一些涉及外键字段的增,删,更新操作之后,需要触发相关操作去检查,而不得不消耗资源;

4.外键还会因为需要请求对其他表内部加锁而容易出现死锁情况;

作者:mysqlops 链接:https://www.zhihu.com/question/19600081/answer/13295957

来源:知乎著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

这里我觉得这个可以拿出来细说,里面提到的点,对数据库服务器的消耗成本还是蛮高的,毕竟关系型DB不知道你想干嘛,他老怕你出错,老帮你检查,数量级一上去,这个消耗就跟着上去。

二、mysql的外键设计问题(对SQL标准的背离)

虽然很多人都不推荐你在关系型数据库使用外键。 但你更多听到的是mysql的,而不是SQLserver或者其他。比较公认的是,他的外键设计得的确不是很好,限制多功能不强大等。(同样的,讨论是不是该用存储过程也存在这种思考)

这里贴上一些从博客园看到的,比较严重的问题。

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

关于对SQL标准的背离(这里只贴其中一个点)

默认的行为应被延迟检查(即约束仅在整个SQL语句被处理之后才被检查)

类似一般的MySQL,在一个插入,删除或更新许多行的SQL语句内,InnoDB逐行检查UNIQUE和FOREIGN KEY约束。

直到InnoDB实现延迟的约束检查之前,一些事情是不可能的,比如删除一个通过外键参考到自身的记录。

详细参考mysql的外键约束 – Johney – 博客园(我发现他也是摘抄MySQL 5.1参考手册的)

三、不使用外键我们也有好的解决方案**

外键是个好东西,他为选择了关系型数据库的我们做了约束和级联做了保障。但不使用物理外键的我们也有方案去实现我们的逻辑外键,并保证他正确运行。

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

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

四、外键对拓展性的限制和影响

计划赶不上变化,外键的主从关系是定的,然后你会因为这个做很多事情,但是万一哪天主键所在表就见鬼去了呢?万一哪天你发现外键表不是非得跟人家的主键挂上关系呢?就我经历过的来看,这种情况并不少见,尤其是数据库设计者水平不够高的情况下。

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

五、反对的声音

最后再来说说一些坚持用外键的思考

有人问:原本在物理外键的开销,在程序上不也有开销吗?的确,但是这样我们对优化性能的方式也灵活了,刚刚说的异步处理就是一种。视具体情况而定,如果设计的好,有时候某些无用数据你不是非得立刻删除他,甚至不是非得删除他。

对于关系型数据库正确性>性能的说法,如果逻辑复杂到一定程度,物理外键一定能给你提供正确性吗?这个可以讨论讨论。

最后,我这里送个东西 MySQL 5.1参考手册

文章目录
  1. 1. 一、外键的性能问题
  2. 2. 二、mysql的外键设计问题(对SQL标准的背离)
  3. 3. 三、不使用外键我们也有好的解决方案**
  4. 4. 四、外键对拓展性的限制和影响
  5. 5. 五、反对的声音