40
zjsxwc
Sep 4, 2021 via Android
@
41
JasonLaw Sep 4, 2021 via iPhone
@
zjsxwc #40 是有一点道理,不过要保证 referential integrity,也只有数据库外键才能做到。
42
alamaya
Sep 4, 2021 via iPhone
@
gBurnX 我可没说不行,只是说没应用层这么简单。也确实没接触过业界有哪些广泛使用、成本低、伸缩自如的数据库集群方案
43
yhkang
Sep 4, 2021
我都快忘了物理外键有什么作用了
44
nuobao
Sep 4, 2021
本小白懂了,以后也不用外键,多一事不如少一事
46
ericls
Sep 4, 2021 via iPhone
不用外键的话 不是得用事务去处理约束? 不是更麻烦吗?
47
pigspy
Sep 4, 2021
我其实挺喜欢外键,个人觉得这玩意是关系型数据库的核心功能之一 但是奈何面向业务编程时,你很难保证领域模型是稳定且准确的,一旦不是,后期的维护和修改的成本会很大,所以干脆在应用层来自己完成外键的逻辑
48
kkbblzq
Sep 4, 2021
程序规模不大的话,也没有性能要求的话,随便吧,否则从程序设计的角度上看,外键会使你的程序对底层 DB 强依赖,其实是不利于程序的扩展的,在不少的分层设计中,仓储层是需要无感知能替换切换的,用了外键就不能实现这一点,而且用了外键,分库分表的之类的就没办法做了,一些分布式的 DB 也基本不支持外键,当 DB 成为瓶颈点再来大改的话反而更麻烦。 另外那个评论的例子,我想知道有没有什么其他有实际意义的场景,以这个例子来看,参照完整性好像没有什么意义,就算是子表多了一条脏数据,其实对业务本身是没有关系的,完全可以后续再清理。
49
kekxv
Sep 4, 2021 via iPhone
讲真的,用数据库进行约束,比应用层去搞好多了,因为你永远不知道下一个改代码的人会对他做什么 而且,你的或者你们公司项目真的在乎那点性能吗?
50
BraveChi
Sep 4, 2021
@
adoal 认识深刻,现在动不动就高并发高可用,其实就是个内网系统,架构整的太大,运行效果反而不如老系统设计合理
52
akira
Sep 5, 2021
外键这种东西,谁爱用谁用,反正我不用
53
JerryCha
Sep 5, 2021 1
因为我们的系统要出生就支持 114514 用户并发,1 分钟承担 1919810 的 transaction
54
Rocketer
Sep 5, 2021 via iPhone
一楼已经说得很清楚了,就是因为需求不明确。 这都不是需求方本身的问题,而是行业发展太快,想明确都明确不了。功能做一半,项目就被砍,然后又去做别的,这都是常态。 现在分布式数据库又不追求强一致,都是最终一致性,你以为数据应该存在而实际找不到的情况是必须要兼容的,这就更不需要外键了。
55
agagega
Sep 5, 2021
@
JasonLaw 前面有层楼也说了,现在的业务有些稀奇古怪的做法,比如假删除,对应到数据库,外键的意义就少了很多。还有一点原因,互联网公司的业务不太追求完整的数据一致性,而外键有可能会影响性能。打个不太合适的比喻:你生活在一个很久都没有确诊病例的地方,打疫苗的意愿肯定不会那么高,因为疫苗副作用概率>感染的概率。
不过,这些习惯可能也就为了降低对开发者数据库技能的要求,把数据库下沉,单纯当一个存内容的地方。所谓保证可移植性这个就比较扯淡了。即使不用外键这些东西,一个 MySQL 的项目要转 PG 也没那么容易的。如果是 scope 很清楚的项目,复杂 join 、存储过程、视图这些用得飞起,应该能轻松不少的。
56
coolcfan
Sep 5, 2021 via Android
好奇 WordPress 用没用外键
57
passerbytiny
Sep 5, 2021 via Android
你首先的区分应用编程还是数据库编程。国内不管哪种语言、用不用 ORM 、用全 ORM 还是用半 ORM,都是应用编程,主编程语言是高级编码语言而不是 SQL,这种情况下物理外键是负担(但逻辑外键仍然存在)。而国外,既有应用编程,也有数据库编程,你用外键作为关键字搜索,结果自然倾向于数据库编程。
59
elboble
Sep 5, 2021 via Android
Python 用 orm 如果不用外键不如直接用 nosql 吧! 萌新看得满头大汗
60
JasonLaw Sep 5, 2021 via iPhone
@
Rocketer #54
我还是不明白,为什么“需求不明确”就开始开工了?就不建议使用外键了?
你说的分布式数据库指的是 NoSQL 数据库吗?
61
JasonLaw Sep 5, 2021 via iPhone
@
agagega #55 同意你所说的“ 互联网公司的业务不太追求完整的数据一致性”
63
Rocketer
Sep 5, 2021 via iPhone
@
JasonLaw 因为踩的坑多了,就知道外键对改需求来说是个累赘。你要非让我具体说个案例,你一定觉得这也没啥,但架不住多啊!烦啊!
关键是为啥一定要用外键?奥卡姆剃刀原则在设计系统时一样有效如无必要,勿增实体。不能因为它在某些角度看起来有好处就无脑用。
一致性对某些场景很重要,但多数互联网企业并不在意这个。据说连支付宝的交易记录都允许出错,每天都会因为对不上账而赔几万块钱。但你要他保证一致性,那成本怕是远远远远远超每天几万块。
64
JasonLaw Sep 5, 2021 via iPhone
@
agagega #55
@
JasonLaw #61
@
Rocketer #63
这里纠正一下,外键跟一致性( Consistency )没有太大的关系,更正确的说法是:外键能够保证 referential integrity 。Consistency 不是数据库本身的一个特性,它是应用怎么使用数据库的一个特性。
65
zjsxwc
Sep 5, 2021 via Android
66
illuz
Sep 5, 2021 via Android
为什么拿 stack overflow 这样的学术性偏强的问答帖子和 v 站水帖比,你可以去搜搜 reddit 帖子或去老外的技术群组讨论,确认一下老外确实大部分都会用 FK 再来提问。 或者直接去捞一些 GitHub 项目,统计一下 FK 的使用情况。 反正我随便搜了一下,发现老外们也有不少不用 FK 的,类似你这样的帖子讨论也不少。
69
zjsxwc
Sep 5, 2021 via Android
@
gBurnX #37
并没觉得有问题,而且业务上负责人不是岗位。
我觉得没必要为了使用外键而修改业务。
70
JasonLaw Sep 5, 2021 via iPhone
@
fengpan567 #68 请问你有使用 primary key, unique 等数据库提供的约束吗?有使用事务吗?
71
msg7086
Sep 5, 2021
所以你说的是数据库物理外键还是说框架里的逻辑外键? 我觉得逻辑外键要有,但是物理外键还是算了吧。 物理外键删数据的时候连 hook 都不会走,天知道会漏跑什么东西。
72
JasonLaw Sep 5, 2021
@
msg7086 #71
更加准确的说,是数据库的 foreign key constraint 。
“物理外键删数据的时候连 hook 都不会走,天知道会漏跑什么东西”是什么意思?可以具体描述一下吗?
73
msg7086
Sep 5, 2021
@
JasonLaw ORM 在执行数据写入的时候是可以往上挂钩子做额外处理的。
举个简单的例子。你有两个表,一个用户表,一个帖子表,帖子外键连到用户。
现在你把一个用户删了,那么这个用户对应的帖子就需要做适当的处理。
比如你可以在用户的删除钩子上,把他发的所有帖子的用户 ID 都改成一个特殊用户的 ID 。
这样那些帖子就不会被删除了。
当然,这个钩子里还可以做其他的操作,比如更新用户的发帖数,更新页面缓存,等等。
而用数据库外键的话,你一做级联删除,这些帖子就消失不见了,你也没法在对象上加钩子来处理这些事件。
换句话说,数据库背着程序做了一些修改,而程序没有感知。
这个行为我觉得是很可怕的。
所以我宁愿让 ORM 来负责一致性。我想级联删除就级联删除,我想用钩子做其他处理,就绑钩子。
77
illuz
Sep 5, 2021 via Android
@
JasonLaw 你这几个帖子里面就有一些非外键派的吧,没有绝大部分哈
78
illuz
Sep 5, 2021 via Android
我只是对帖上文的 stack overflow 和 v2 对比方式表达一下看法,感觉这个讨论前提不够有力
79
skiy
Sep 5, 2021
@
gBurnX 关于准确这个方面, 这个说得没错. 但你 `mysqldump` 出来一个库后, 然后直接 `source` 进去却报错. 这个你受得了? 试想几百个表, 然后还要一个一个地对比着先后顺序吗? 如果没有文档说明, 没人会想到会是这种问题. 当初我就是吃过这方面的亏. (我不是专业的 DBA)
80
azuis
Sep 5, 2021 via iPhone
@
skiy 导入导出的时候问题不大吧。可以暂时禁用外键检查,导入完成后再启用即可。
81
JasonLaw Sep 5, 2021 via iPhone
@
illuz #78 所以我在#67 贴出了 reddit 上的一些讨论
82
makelove
Sep 5, 2021
@
skiy 先不说我从来没碰到过导入导出会出现外键问题(印象中会自动禁用外键),即使有你不可以先禁止外键检查导入完后再启用吗
84
skiy
Sep 5, 2021
@
makelove 我都说当初了. 默认是不禁止的. 当时还不了解, 以为程序有问题... 折腾.
85
JasonLaw Sep 5, 2021 via iPhone
@
skiy #84 让我想起了以下这几段话。(来源:
https://stackoverflow.com/a/85298/5232255 )
This is an issue of upbringing. If somewhere in your educational or professional career you spent time feeding and caring for databases (or worked closely with talented folks who did), then the fundamental tenets of entities and relationships are well-ingrained in your thought process. Among those rudiments is how/when/why to specify keys in your database (primary, foreign and perhaps alternate). It's second nature.
If, however, you've not had such a thorough or positive experience in your past with RDBMS-related endeavors, then you've likely not been exposed to such information. Or perhaps your past includes immersion in an environment that was vociferously anti-database (e.g., "those DBAs are idiots - we few, we chosen few java/c# code slingers will save the day"), in which case you might be vehemently opposed to the arcane babblings of some dweeb telling you that FKs (and the constraints they can imply) really are important if you'd just listen.
Most everyone was taught when they were kids that brushing your teeth was important. Can you get by without it? Sure, but somewhere down the line you'll have less teeth available than you could have if you had brushed after every meal. If moms and dads were responsible enough to cover database design as well as oral hygiene, we wouldn't be having this conversation. :-)
86
Rache1
Sep 5, 2021
@
skiy 这个倒是可以在 SQL 前后临时禁用外键,一般 SQL 插入的时候也可以,就是要多敲一个命令,比较麻烦
87
skiy
Sep 5, 2021
@
JasonLaw 存在就有其道理. 使用场景的问题. 我刚才就说我不是专业的 DBA. 对于这块不了解, 也没打算要对这块有多了解.
88
ikas
Sep 5, 2021
往前推 10 多年吧,那时候 db 设计比现在严格多了..何止外键.表的关系都是严格设计.class 也都是严格写好映射.... 只不过是软件行业发展很快,需求大,变化多,时间少....
89
skiy
Sep 5, 2021
@
Rache1 知道. 当初用的人家的一个开源的网站程序. 备份时直接用的 mysqldump 备份了. 有时候基础命令我很少带参数去操作的, 都是用默认的设置. 后来解决了.
90
wqtacc
Sep 5, 2021
@
JasonLaw #15 的问题,不就是插入前检查父属性存不存在的问题么,把检查和插入写一个事务里,这样也是符合程序逻辑的;你看没有事务的情况下,在程序里是一个完整的过程。我们不用外键,也不是连事务一起都丢掉。
91
wangxin13g
Sep 5, 2021
个人看法是 外键 触发器 存储过程都是面向实现的依赖 具体点说就是你依赖了某个 SQL 数据库的某个功能,这对后面无论是迁移数据库还是接手的人理清逻辑都是百害无一利的
92
fkdog
Sep 5, 2021
@
JasonLaw 外键的两个用途,级联更新和级联删除。
级联更新:大部分的外键一般都是设置为主键或者其他值固定的字段,因此级联更新一般意义不大。
级联删除:为了监管 /数据误操作恢复等原因,大型互联网公司基本都是采用 update 软删除而非 delete 物理删除,因此级联删除意义也不大。
此外,由于现代大型系统都是分布式的。如果你的外键对象不在一个库里那么你无法加上外键约束。此外由于一些数据库中间件,读写分离、高可用、异步等,可能会出现数据延迟的情况,那么这种情况可能就会出现外键异常导致插入失败的情况。
所以综上,外键约束在大型系统里是一个很鸡肋的存在。
至于你说的 orphan 问题,外键检查完全是可以通过代码来实现的。
外键这东西放到今天其实有点学院派的味道,而且很多国外会用到外键也是由于类似 hibernate orm 之类的东西在后边自动帮你加上去了。这东西和数据库范式是一个道理,理论上说遵循范式不要有数据冗余,但是实际上冗余数据在今天反而是一个解决跨库跨表非常常用的手段。
94
makelove
Sep 5, 2021
@
fkdog 不要拿极端用例当普遍情况,你所说的大型互联网公司里的大型应用又有几个呢?一般单个数据库一个主从足够了,特别是现在有了大容量高速 SSD 不是千万级以上的用户还真用不上极端的性能手段。
95
fkdog
Sep 5, 2021 1
@
makelove 删除一个 user,直接清空了与该 user 有关联的所有表的所有数据,这就是你期望看到的?
如果碰到根据实际场景动态决定是否需要删除关联表的数据的需求,你设置这种外键不是给自己找麻烦?
就算设置外键,一般也是关联到主键 id 或者其他一些不变的唯一 id 上,这种场合下你级联更新用得上地方?
连这些都被你描述成“极端场景”了,那我也建议你不要拿你的那点 simple crud 经验指点别人。再不多长进长进,过几年 crud 自动生成插件都能把你给淘汰了呢。
98
JasonLaw Sep 5, 2021 via iPhone
@
fkdog #95 希望大家都就事论事,不要说有的没的。外键最重要的作用是保证 referential integrity 。关于“ 删除一个 user,直接清空了与该 user 有关联的所有表的所有数据”,这个是显式声明了 ON DELETE CASCADE 。
99
fkdog
Sep 5, 2021
@
JasonLaw 建议你不要把这些东西当成圣经。
我举个很常见的例子,比如很多数据库为了索引优化,会给索引列设置一个默认值避免因为 NULL 造成的无效索引,比如给字段设置-1,0 等。假如这一列恰好是外键列,而-1,0 对应在父表中的关联对象是不存在的,这显然是违反了引用完整性。
所以你是要考虑你理想的引用完整呢,还是考虑实用主义优化性能为主?
我发现 v2 上的人真的很喜欢把一些东西当圣经奉为圭臬。。
比如 restful 和业务 code 封装就能争出上百条评论。
理想主义者遍地,孤芳自赏,还要抱团取暖。
ubao
msn
snddm
index
pchome
yahoo
rakuten
mypaper
meadowduck
bidyahoo
youbao
zxmzxm
asda
bnvcg
cvbfg
dfscv
mmhjk
xxddc
yybgb
zznbn
ccubao
uaitu
acv
GXCV
ET
GDG
YH
FG
BCVB
FJFH
CBRE
CBC
GDG
ET54
WRWR
RWER
WREW
WRWER
RWER
SDG
EW
SF
DSFSF
fbbs
ubao
fhd
dfg
ewr
dg
df
ewwr
ewwr
et
ruyut
utut
dfg
fgd
gdfgt
etg
dfgt
dfgd
ert4
gd
fgg
wr
235
wer3
we
vsdf
sdf
gdf
ert
xcv
sdf
rwer
hfd
dfg
cvb
rwf
afb
dfh
jgh
bmn
lgh
rty
gfds
cxv
xcv
xcs
vdas
fdf
fgd
cv
sdf
tert
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
sdf
shasha9178
shasha9178
shasha9178
shasha9178
shasha9178
liflif2
liflif2
liflif2
liflif2
liflif2
liblib3
liblib3
liblib3
liblib3
liblib3
zhazha444
zhazha444
zhazha444
zhazha444
zhazha444
dende5
dende
denden
denden2
denden21
fenfen9
fenf619
fen619
fenfe9
fe619
sdf
sdf
sdf
sdf
sdf
zhazh90
zhazh0
zhaa50
zha90
zh590
zho
zhoz
zhozh
zhozho
zhozho2
lislis
lls95
lili95
lils5
liss9
sdf0ty987
sdft876
sdft9876
sdf09876
sd0t9876
sdf0ty98
sdf0976
sdf0ty986
sdf0ty96
sdf0t76
sdf0876
df0ty98
sf0t876
sd0ty76
sdy76
sdf76
sdf0t76
sdf0ty9
sdf0ty98
sdf0ty987
sdf0ty98
sdf6676
sdf876
sd876
sd876
sdf6
sdf6
sdf9876
sdf0t
sdf06
sdf0ty9776
sdf0ty9776
sdf0ty76
sdf8876
sdf0t
sd6
sdf06
s688876
sd688
sdf86