数据库表设计中建议添加外键么

数据库 专栏收录该内容
10 篇文章 0 订阅

通过从知乎帖子的讨论进行整理如下:
先给出结论:

结论

外键是否采用看业务应用场景,以及开发成本的,大致列下什么时候适合,
什么时候不适合使用:

互联网行业应用不推荐使用外键: 用户量大,并发度高,为此数据库服务器很容易成为性能瓶颈,尤其受IO能力限制,且不能轻易地水平扩展;若是把数据一致性的控制放到事务中,也即让应用服务器承担此部分的压力,而引用服务器一般都是可以做到轻松地水平的伸缩;

什么时候适合使用了:

传统行业
1>.软件应用的人数有限,换句话说是可控的;
2>.数据库服务器的数据量也一般不会超大,且活跃数据有限;
综合上述2句话描述,也即数据库服务器的性能不是问题,所以不用过多考虑性能的问题;另外,使用外键可以降低开发成本,借助数据库产品自身的触发器可以实现表与关联表之间的数据一致性和更新;最后一点,使用外键的方式,还可以做到开发人员和数据库设计人员的分工,可以为程序员承担更多的工作量;

为何说外键有性能问题:

  1. 数据库需要维护外键的内部管理;
  2. 外键等于把数据的一致性事务实现,全部交给数据库服务器完成;
  3. 有了外键,当做一些涉及外键字段的增,删,更新操作之后,需要触发相关操作去检查,而不得不消耗资源;
  4. 外键还会因为需要请求对其他表内部加锁而容易出现死锁情况;

不建议

  1. 响马
    不想做程序员的程序员不是好程序员……
    232 人赞同了该回答
    数据库的诸多设计,帐号,权限,约束,触发器,都是为 C/S 结构设计的,是以 C 端不可信做为假设前提的。B/S 模式安全边界前移到 web 服务层,应用与数据库之间是可信的,应用自行完成这些功能更加灵活。
    所以能不用就不用。

  2. 李楠
    55 人赞同了该回答
    因为很多答案对但是不精到,我再回答一个。
    这实际上不是个数据库问题,而是个架构问题。
    使用外键与否,看你使用的框架是否有足够的事务管理能力。
    (其实不仅限于外键,还有一切可被替代的 db 高级特性)
    如果足够,那么应该尽量避免。理由很简单:app server 比 db server 便宜,而且拓展容易。

  3. Fenng
    71 人赞同了该回答
    怎么总有人问我数据库的问题…透露一个秘密,我在前公司的时候摘掉了所有的外键。业务约束通过中间层控制。面向Web的应用应该这样。一个DBA是否有足够的设计能力,就看他有多大的能力做反范式设计就可以了。不要问为什么。

  4. 鲁塔弗
    6 人赞同了该回答
    外键在早期企业系统数据库设计里面比较多吧,本意是好了,帮程序员节省delete,update操作,实际上增加了潜规则,也增加了软件复杂度。互联网应用中,一般流量比较大,数据库当memecache用,大表+冗余字段,索引还建在外部用sphinx之类,基本上没有表和表的关联关系,外键无用

中间派

  1. vczh
    72 人赞同了该回答
    【update, delete等操作都会涉及相关的表】什么的,这是需求的一部分啊,不是你从C/S改成B/S就可以不算的。
    我举个简单的例子,我table1存学生的信息,另table2存学生没一次考试的信息,那table2的id就是指向table1的foreign key,没错吧。这个时候你把学生x的信息删掉了,你所说的不希望【update, delete等操作都会涉及相关的表】的意思就是,他的成绩我还留着!
    这有两个后果
    1:万一你的新人的id给你重用了,你的数据库就毁了
    2:长此以往,垃圾数据一大堆啊
    所以一定要让你在删除学生的时候给你当头一棒,告诉你要先删成绩,再删人。这是多么合理的做法。

  2. 孙文亮
    12 人赞同了该回答
    我想,这取决于数据库的用途、规模、架构,有外键,可以提高鲁棒性、健壮性,但是约束检验显然会拖慢速度。
    规模上说,数据量大的不适合用外键,小的可以用;用途上安全性、可靠性很重要的就要用外键,否则可以不用。具体情况具体解决了,因为也有矛盾的时候,数据量极大,但是又要求高可靠,例如银行金融、芯片生产等,仍然需要外键的存在。可以通过SAN+RAID等硬件提升解决矛盾。
    要求高并发的情况下,并不适合外键,有的连关系数据库都不用了,甚至数据库都不用了。
    这类问题真没有绝对的答案,什么情况下该怎样做,只能是多想,多做了,错的多了,就懂了。

  3. 李遥
    A Programmer
    10 人赞同了该回答
    除非为了提高性能没有任何其他办法可以用了,否则不要取消外键。数据被错误覆写、错误数据进库(会引发不可预期的连锁反应)往往是比程序错误更难修复的错误,有时甚至不能修复
    我通常不仅加足外键,还狂加约束,一直被称为“约束狂人”。我写的代码在所有非性能关键路径上全是各种检查,Release版也保留。优化的话则从顶层入手、从整体入手。我做过这么多项目从来没有遇到什么问题

  4. zhai
    持续构建技术之体系,立工匠之精神。
    1 人赞同了该回答
    阿里JAVA规范:【强制】不得使用外键与级联,一切外键概念必须在应用层解决。
    做为一种对待外键的理念, 无可厚非。
    如果要遵照这个理念的话,需要补充一句: 不键立外键可以, 但是应在外键的列上应当建上索引。
    如果不建索引, 在根据外键update, 或delete时的代价也不可承受!
    外键使用的重度分类
    1、不使用外键 (不建索引, 很可怕)。
    2、不使用外键但必建立索引 (给不采用外键的人)。
    2、使用外键,不级联(给采用了外键的人)。。
    3、使用外键,且级联操作 (一般不要采用)。

如果不设置外键,需要增加什么方案了

你非要真执行DELETE才行么?UPDATE employees SET status = “leaved” WHERE id = ?;不就好了?如果涉及隐私的话就把ID之外都清空,一了百了。
vczh (作者) 回复Cosmia Fu5 年前
这样你就要在所有的业务逻辑里面先判断他是不是leave然后才能执行什么操作了这简直无法接受,数据都没删,还给自己添加麻烦。想在transaction里面写句if可不是那么容易的事情
Cosmia Fu
Cosmia Fu回复vczh (作者) 5 年前
为防止误会,我先说我是支持添加实际的fkey的,不过垃圾数据为何很难界定,所以保险的做法是能留着的都流着,实在嫌麻烦可以在删除时保存到另外一个数据库中去,而且,应该没有人会「频繁」操作Raw SQL吧,做个middleware处理这个field不就
楚梓桐回复Cosmia Fu3 年前
难道不是left么……
​赞
一般搞互联网的从来都不会做真的DEL,最多加个标志位,当然也不会用外键
一村宅男回复刘照云2 年前
Delete真的很坑爹
GuoFu
GuoFu2 年前
这个删除逻辑就有问题。随着业务演进,使用delete语句的机会会越来越少。除非日志类的记录,否则不应该使用delete语句,而是使用isDelete状态,或则就是一列state列,用来控制一行数据的生命周期。
我觉得应该更多用事务,感觉要保证一点点数据库的纯粹性。数据库就是存数据的不要处理过多逻辑。
知乎用户知乎用户1 年前
哎,轮子哥这么好的回答已经没有了。知乎完了
纯洁1 年前
首先,真删本就不好,用一个is_del状态来表示是否删除,说到这垃圾数据,可以写个清理脚本,定期运行去清理。而且很多时候有点数据冗余没问题的,为了这么一点无关紧要的准确性而牺牲这么大的性能,不值。查成绩这个,程序逻辑层可以每查一张表时都做个空判断。
[^1 ] 大家设计数据库时使用外键吗?

  • 1
    点赞
  • 0
    评论
  • 1
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

©️2021 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值