前言:
在关系型数据库中,可以使用外键来建立表与表之间的关联关系。外键是一个字段或一组字段,用于建立从一个表(称为子表)到另一个表(称为父表)的引用关系。
外键的作用
MySQL 外键最大的作用就是有助于维护数据的一致性和完整性。
- 一致性:如果一个订单表引用了一个客户表的外键,外键可以确保订单的客户 ID 存在于客户表中,从而保持数据的一致性。
- 完整性:外键可以防止在引用表中删除正在被其他表引用的记录,从而维护数据的完整性。
但是,其实在很多大型互联网公司中,很少用外键的,甚至阿里巴巴Java开发手册中明确规定了:
外键带来的问题
先举个例子,我们有两张表:Orders(订单)和Orderltems(订单项)。这两个表之间通过外键建立关系,订单项表中的外键引用订单表的订单号。
接下来基于这两张表展开分析。
性能问题
首先就是性能问题,因为外键会增加数据库的维护负担,因为每次插入、更新或删除数据时,数据库都需要检查外键约束的完整性。
首先,这两张表中共有两个索引,一个是Orders表的主键索引,一个是Ordersltems表的外键索引,这就使得每次插入、更新或删除订单或订单项时,数据库需都要维护这两个索引这可能会导致性能开销。
其次,在插入新的订单项之前,数据库需要执行数据一致性检查以确保引用的订单号在Orders 表中存在。这额外的检查可能增加插入订单项的执行时间。
锁竞争问题
还有就是比较容易忽略的锁竞争问题。当多个事务同时尝试插入或更新订单项时,它们就需要去检查订单表,就需要获得额外的锁,以确保一致性。这可能导致事务之间的锁竞争,降低并发性能。
一旦有了锁竞争,就可能带来更加严重的死锁问题,所以都是需要尽量避免的。
无法适应分库分表
当数据量大的时候,我们就要考虑分库分表了,但是在分库分表环境中,相关数据可能分布在不同的数据库中,外键通常难以跨越不同数据库来建立关系。更重要的是,分库分表环境中,数据的一致性可能更难维护。跨库事务搞不定。
以上,就是一些比较重要的原因吧。其其实最主要的还是外键约束会带来一些额外的开销及锁竞争。而在很多大型互联网公司中,都是会尽量避免的。
就像大厂会使用RC来替代RR一样,会尽可能的降低锁的发生,一方面提升性能,一方面避免死锁。
逻辑删除
我们在很多时候,都不会直接删除数据,而是通过逻辑删除进行,而外键在逻辑删除中会有一些约束。如:
1、外键是一种物理约束,而我们业务当中更多用的是逻辑删除。
2、加了外键之后必须先删子表,再删主表,而更多情况下都是先对主表做逻辑删除,再对子表做统一处理。
总结
建表外键的作用是确保数据的完整性、一致性和关联性,提高数据库的数据质量和查询效率。它是关系型数据库中常用的一种约束机制,有助于保证数据的正确性和可靠性。但是外键还会带来好多问题,其实我们现在做的最多的是通过代码逻辑来约束和关联表之间的关系。