关于外键,为什么国内基本都不推荐使用,国外基本都推荐使用?

2021-09-04 17:38:25 +08:00
 JasonLaw

国内的一些讨论:

国外的一些讨论:

16452 次点击
所在节点    程序员
128 条回复
JasonLaw
2021-09-05 16:52:35 +08:00
@fkdog #99 “NULL 造成无效索引”?

https://tanronggui.xyz/t/694500
jiayong2793
2021-09-05 17:01:52 +08:00
我还以为只有.net 是这样,没想到其他都是这样,直接用代码关联各个表
mreasonyang
2021-09-05 17:05:00 +08:00
没想到 2021 年还有很多人在争论是否该使用关系型数据库的外键,这种外键我们更习惯称其为物理外键,与之相对的是由业务逻辑控制的逻辑外键,实际上当今稍稍复杂些的业务都在使用外键,只是使用的是逻辑外键而非物理外键。

物理外键是我们学习数据库原理和设计时都会遇到的章节,它的主要优势是可以通过数据库实现强制的 Referential Integrity,即引用完整性。但这样的完整性使用逻辑外键也完全能实现,有人认为逻辑外键由于完全依赖业务代码所以无法真正保证完整性,但这其实是个伪命题,因为物理外键也是由「人」来设置的,你只能保证设置过的物理外键能保证引用完整性,至于那些没考虑到的、设计错误的数据关联关系仍然是物理外键无法解决的,在这一点上物理外键和逻辑外键是没有实质区别的。而实际上当今的云原生架构在数据层面追求的是分布式和最终一致性,单个 DB 存储所有数据的时代早已过去,数据在服务间流转已经是常态,此外国内场景下很多数据也不被允许直接物理删除,物理外键的作用在现代架构下变得微乎其微。物理外键不是银弹,它甚至都没有成为银弹的实力。

而说到劣势,物理外键在现代后端架构中的缺点已经越发明显。分场景分析如下:

- 对于传统企业应用,交付后几乎没有大面积迭代,使用物理外键是无可厚非的,这也是对传统软件开发模式和架构的传承。但现在有越来越多的企业选择使用 SaaS 或自主进行研发和维护,这也就意味着产品的迭代会比此前频繁得多,进而变为下文提到的流量小但迭代频繁的项目。
- 玩具型项目用不用外键都没有区别。
- 大流量项目使用物理外键无疑是在埋坑,抛开颇受争议的性能问题不谈,物理外键无法满足分库分表、单元化等现代架构设计的需要,甚至在这些架构下还会成为累赘要额外花费时间改造掉。
- 小流量项目的迭代速度可不慢,领域模型很难稳定下来,而使用了物理外键也就意味着系统是基于数据库进行的建模,那么当前的物理外键设计迟早有一天要面临变更,这所带来的维护成本(改表困难、业务拆分和聚合困难等)是巨大的,这也是为什么现在很少有人使用存储过程的原因。

可见物理外键在数据模型迭代频繁以及大流量场景下具有非常明显的劣势。

其次是职责问题,在人员职责上,DBA 与业务强耦合本身就是不合理的,这和为什么要做前后端分离是一个道理,这也是为什么当今很多互联网公司会选择一名 DBA 对接一个后端大组甚至事业部的原因,DBA 的职责已经下沉到更核心的数据库稳定性和性能提升上。而在架构中的分层职责上,在持久层耦合业务逻辑是非常不明智的,因为这意味着你的架构会严重依赖某个数据库选型甚至某个特定版本数据库的功能,领域模型与数据模型的耦合也会产生很多人噩梦中的一个 Service 层走天下的情况,业务逻辑很难做进一步的抽象和拆分,至于读写模型分离、CQRS 也就是更不可能的事情了。

综上,使用物理外键能带来收益非常有限,但隐性成本(只要业务还在发展,那未来早晚会变为显性成本)却非常高,其本身又可以被逻辑外键所替代,那除了个人或团队喜好,我实在找不到继续使用物理外键的理由。
sy20030260
2021-09-05 17:06:05 +08:00
@JasonLaw 且不说国外外键用得比较多作为「事实」成不成立吧(毕竟没有真实数据支撑)
就算事实成立,也顶多就说明国外小厂生态比较好,或者国外小厂程序员的社区活跃度比较高,总之我想和外键这一技术本身不会有太大关系
fkdog
2021-09-05 17:33:25 +08:00
@JasonLaw https://segmentfault.com/a/1190000023480072
刚好从 evernote 里找到去年剪藏的文章。
文章里的测试结果,我在 mysql5.7 版本上复现。
noparking188
2021-09-05 18:00:41 +08:00
@mreasonyang #103 俺也一样!
wangkun025
2021-09-05 19:56:06 +08:00
@agagega rails 默认是使用外键的。
iyaozhen
2021-09-05 22:01:49 +08:00
我提供一些其它参考吧
因为我们要 to b,遇到的数据库很不标准,既有 MySQL 也有各种云的,还有 newsql,甚至还有国产数据库。用外键那不是没事找事嘛。之前做 Oracle 系项目何止外键,存储过程啥的都用的飞起。
ragnaroks
2021-09-05 23:39:29 +08:00
@JasonLaw
冲突可以被缓存器解决,比如 steam 送礼物给任意未注册邮箱的实现

@gBurnX
使用外键降低数据库服务器的性能,不使用外键降低 N 个 web 服务器其中 1 个机器的性能
gBurnX
2021-09-06 00:11:00 +08:00
@ragnaroks

你觉得不用外键,数据库服务器就可以在一旁看戏啦?再想想?
chengyiqun
2021-09-06 10:23:08 +08:00
其实基本大家都在用分布式数据库分表分库, 用不了外键吧.
JasonLaw
2021-09-06 10:31:47 +08:00
@chengyiqun #111 SQL ? NoSQL ?还是 NewSQL ?
ragnaroks
2021-09-06 10:33:49 +08:00
@gBurnX web 服务器都是边缘节点了,数据库还是一个?再想想?
JasonLaw
2021-09-06 10:41:34 +08:00
我感觉讨论下去没有太大意义了,没有一个事情是绝对的,每个东西都有它适用的场景。
SmiteChow
2021-09-06 10:48:03 +08:00
因为国内大多数英语半吊水平不足以阅读专业文档重用数据库,所以只能把数据库当文件系统用,其他自己写,为了美化这种行为,编造各种话题。
FightPig
2021-09-06 11:00:23 +08:00
@agagega Rails 默认是用的,rails g model post title user:belongs_to 会生成

```
t.belongs_to :user, null: false, foreign_key: true
``
veike
2021-09-06 12:26:40 +08:00
@SmiteChow 你是说国内互联网大厂里都数据库专家英语都是半吊子吗😁
gBurnX
2021-09-07 00:51:49 +08:00
@ragnaroks

数据库服务器是多个就不会降低数据库服务器的性能?再想想?
ragnaroks
2021-09-07 01:29:42 +08:00
@gBurnX
是的,当处理能力远大于压力时,不存在降低数据库性能的前提。
36 个同步主库(基于 uuid 首字符做分库),70 多个从库,CPU 从未高于 50%,主库甚至可以配置远低于从库。
你上面的这些想法,在我看来是从未实际生产过,有这些天马行空的想法。

我能想到的大概只有学生为了完成老师布置的作业,去阿里云买了一台超售 VPS,跑一个数据库,CPU 直接见底。
MeteorCat
2021-09-07 09:05:04 +08:00
大部分公司没有专业 DBA, 外键管理基本上是业务来编写处理

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://tanronggui.xyz/t/799876

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX