0
点赞
收藏
分享

微信扫一扫

MySQL 高级特性(五):为什么不推荐你使用外键?

前程有光 2021-09-25 阅读 165

目前,在 MySQL 内置存储引擎中,只剩下 InnoDB 还在支持外键,因此如果要使用外键可选择的存储引擎不多。

外键并不是没有代价的。事实上,外键通常会需要服务器地在更改数据的时候检查另一张表。尽管 InnoDB 使用了索引提高这个操作速度,但并没有让数据检查的影响消失。甚至还可能产生一个很大的没有筛选性的索引。例如,假设我们在大的数据表中有个 status 字段,然后约束 status 只能使用有效的值,然而这个值只有三个可选项。这会导致额外的索引大大增加数据表的存储空间大小,即便是这个列自身存储空间很少。尤其是当主键存储空间比较大时,而这个索引除了用于外键检查,通常没什么用。

当然,外键在某些情况也能够改善性能。如果我们需要保证两个关联表的数据必须保持一致的时候,使用 MySQL 服务器进行检测会比程序来检测效率更高。外键在那种级联删除或更新的场合也很有用。但是这类操作是逐行进行的,因此会比批量删除或批量操作更慢。

外键导致查询需要依赖其他数据表,这意味着 InnoDB 需要在父级表(或相关表)中检验相应的值。这也会锁定父级表的数据行,以保证在事务完成前该行不会被删除。这会导致意外的锁等待,甚至是死锁,这类问题很难被定位。

既然外键有如此多的缺陷,因此可以使用别的方式替代外键。一种方式是使用触发器替代外键。外键的目的是在类似级联更新的时候触发任务自动关联。对于那些仅仅是约束值的外键,例如之前谈到的 status 例子,可以通过一个明确的可用值列表的触发器重写(也可以使用 ENUM 枚举类型)。

另一种方式是使用程序来完成类似外键的约束。外键可能会显著增加负荷,这个虽然没法准确度量,但是实际确实发生过很多由于外键约束检查引起的性能问题,而且移除外键后性能能够得到显著提升。

举报

相关推荐

0 条评论