数据库的本质是存储数据,在这个之上还要维护数据的完整性。在维护完整性数据库提供几种方法,一种是事务,一种是外键 FK。这两种方式是分别处理两种情况,事务处理的是多个表中记录的原子性,FK 是处理多条有关系的记录。

举个外键例子来说,假如有一个资源管理系统,你申请了许多资源,有电脑、账号、书籍、笔记本等好多东西,在你离职时候,这些记录需要全部删除,同时你的账号也要从这个系统中删除。这时候如果存在外键,user 表中的 id 字段关联了各种的资源 id,这时候需要一条 SQL 就可以删除这些记录。

所以这么看外键貌似很有用,真实情况是真的很有用。但是我们从给一个角度来看,一条 SQL 需要级联多个表的操作,在 DB 引擎中可能同时需要多个行锁或者表锁,来保证完整性。同时还会会涉及到 IO 问题,我们都知道 IO 的随机读写其实是比较慢的,在访问频繁的的时候数据库往往不足以支撑那么大量的请求。

一般这种观点的人会给出以下几个理由:

  • 性能好
  • 修改开放,易于维护

坚持使用外键的人也有几个理由:

  • 数据完整性
  • 表结构清晰
  • 约束性好

无论怎么看都貌似很有道理,事实就是都对,但是要看在什么情况下使用,要从架构层面上取长补短。假如我们使用了无外键的设计,那么就要从架构补足缺点。举个例子来说,无外键设计一般会上移逻辑层到程序中,由程序要维护数据完整性,随着程序重启崩溃总是会出现一些游离数据。这些游离数据对系统究竟没有影响就很关键了,如果说这些游离数据不会影响系统正常运行,那么无外键的设计就很成功。典型的就是只需要根据 id 来获取某些数据,而不是通过某些条件来范围查询数据。

这个其实很好理解,对于只用 id 获取的数据我只要保证这个 id 有没有没有被删除就 ok 了,那些关联的数据在这个 id 被删除以后就再也无法被找到了。

如果说你正在做的是一个账号相关的系统,往往和账号相关的数据要求的完整性都很高,无法容忍出现游离数据,那么你只能使用外键来维护这种关系,虽然说上移到程序也能做,但是总不如数据库来的彻底。

对于访问量大的表来说,一般会对这个表分片处理,分片的原理是根据某个字段把数据分散到多个片当中,这时候外键就无法起作用了,对于互联网公司来说分片做的都很多,外键设计变得越来越少。精明的架构师会用各种方法来补足无外键的缺点。

总结一下,关于是不是要外键的回答可以肯定的是,要和不要都可以。具体要看业务如何拆分,数据容忍度有多高,以及架构师是否精明。如果以上没有一个,那么还是老老实实使用外键设计。