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

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

国内的一些讨论:

国外的一些讨论:

15259 次点击
所在节点    程序员
128 条回复
JasonLaw
2021-09-04 20:29:00 +08:00
@alamaya #19 应用层实现逻辑外键的话,比如我回复主题的时候需要检查主题是否存在,应用层检查难道不会给数据库增加压力?
JasonLaw
2021-09-04 20:30:37 +08:00
@zjsxwc #20 关于“ 外键循环死锁依赖”,可以举个简单的例子吗?
makelove
2021-09-04 20:31:09 +08:00
外键几乎没有编程上的额外负担,却能增加数据的可靠性,降低后期维护的成本
且有时编程上也方便比如可以级联删除
坏处无非是性能上的极少量损失,真的有热点表在乎这点损失就在那个表上不用外键就行了何必整个都不要了
zjsxwc
2021-09-04 20:33:35 +08:00
@JasonLaw https://blog.csdn.net/aaaaaalll/article/details/80742064
这种已经是简化了的场景,实际情况更加复杂,会有各种花式依赖。
zjsxwc
2021-09-04 20:35:40 +08:00
不过也看业务,业务简单,后期不会修改业务,实体类关系是树状的用外键最爽。
chinvo
2021-09-04 20:45:09 +08:00
"外键增加额外性能开销"的这类说法, 是把不用外键时执行插入操作之前的 select 的数据库性能开销+网络 IO 开销当不存在么...
wqtacc
2021-09-04 20:50:02 +08:00
现在的目的就是用来存数据,利用数据库的查询能力,至于外键的约束,虽然不在数据库使用,应用实现时这个关系还时有的
JasonLaw
2021-09-04 21:02:04 +08:00
@wqtacc #27 那怎么解决#15 所描述的问题?再激进一点的话,那还要事务干嘛,直接应用层解决不行吗?干嘛让数据库做这么多事情来保证 AID ?
alamaya
2021-09-04 21:04:00 +08:00
@JasonLaw 对读的优化手段要多少有多少,数据库读和写的吞吐量都不在一个数量级,读的性能可以靠加机器解决,写却没那么简单
你说的这个场景,加个被动缓存就解决的事儿,对数据库来说能有多大压力呢
wangbenjun5
2021-09-04 21:07:57 +08:00
@JasonLaw 真没人用这玩意,外键这玩意就和触发器、存储过程一样,属于上古时期重数据库开发模式的遗留产物。。。不是还有什么数据库编程么,还能在数据库层写 if else,你敢用?
adoal
2021-09-04 21:16:28 +08:00
因为国内现在主流的一批所谓架构师都是 BAT 等几个互联网大厂出来的。甚至是做行业信息化的圈子也被互联网技术路线污染了,导致屁大点并发量但是业务规则较为复杂的系统也在盲目使用互联网大厂所面临的秒杀、热评场景下用的架构。
JasonLaw
2021-09-04 21:19:15 +08:00
@alamaya #29 这样子的话,你也无法达到数据库外键所能实现的效果,应用代码还复杂多了。
gBurnX
2021-09-04 21:21:31 +08:00
1.外键是一种规范与约束,一定要有,但不一定要用数据库去实现。

2.外键功能,到底用数据库去实现,还是用代码实现,要看成本。这里的成本,有员工成本,与服务器成本两个因素。

用数据库实现外键,员工成本小,服务器成本高。但国外,员工工资贵,服务器相反会便宜些,而国内相反,这是主要因素。

3.国外人少,内卷小,而且各自行业规范多,员工职业素质高,做事规范,自然要用外键,这是原因二。反观国内,竞争太激烈了,甲方爸爸加需求完全不管合同,乙方不给加,甲方爸爸分分钟找个新乙方做,而且事情传出去,以后乙方不用混了。

甲方爸爸天天加需求,数据库表一天加好几个,你要用外键,每次还得梳理一遍,很麻烦。

4.外键不是造成死锁的原因,避免死锁,首先要设计表要规范化,其次在事务中需要锁表时,一定要按同意顺序进行锁表。
gBurnX
2021-09-04 21:24:57 +08:00
@skiy

你说的这个缺点,其实正是外键的优点。

你想想,如果没有外键来约束导入顺序,你先导入 A,怎么保证 A 的数据中包含的 B 就一定正确?正确包括且不限于 B 存在且不冲突。
gBurnX
2021-09-04 21:25:34 +08:00
@ragnaroks

如果你用的词是 [降低性能] ,那么不用外键,也会降低性能的。仔细想想?
gBurnX
2021-09-04 21:26:23 +08:00
@alamaya 为什么应用层能横向扩展加机器,数据库就不行?
gBurnX
2021-09-04 21:30:21 +08:00
@zjsxwc

造成死锁有很多原因,比如建表建模不规范,或者锁表不按统一顺序,或者业务冲突等等。

你提的这个原因,是属于建表建模不规范。

本来已经有了岗位表,来说明每个员工在部门里的位置,为什么非得在部门表里再设计一个对于岗位的冗余?而且还是拿员工表来做的冗余,这种设计,直接导致两个表互为外键,属于错误的建模建表方式。正确的做法,应该是在岗位表里添加字段,来说明员工在部门里的位置。并且包含关系,从大到小依次为:部门 -> 岗位 -> 员工。
JasonLaw
2021-09-04 21:30:22 +08:00
@zjsxwc #24 个人感觉,这个是设计的问题,不是外键的问题,不在部门表存储负责人就行了,使用关系表解决。想象一下,把三个实体当作 Spring 中的 service 的话,它们也会造成循环依赖。
JasonLaw
2021-09-04 21:34:05 +08:00
@gBurnX #37 同意
zjsxwc
2021-09-04 21:43:01 +08:00
@JasonLaw #15

实际业务中 不怕数据多了,而是怕数据丢失,
comment 变 orphan 不可怕,甚至业务中你的 answer 也不是真删除而只是把 status 字段改成某个代表删除的值,于是对于这种业务来说外键约束级联删除都触发不了,这种伪删除的业务存在导致了数据库外键作用消失,外键只剩下 index 加速查询的作用。


忽然想到,

要用外键的一个 非常非常 重要的前提是你 真正的真实的 在删数据!!!!!!!而不是标记下伪删除。

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

https://www.v2ex.com/t/799876

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

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

© 2021 V2EX