设计数据库究竟使用不使用外键?

因为需要设计表,也遇到了一些问题,比如其中一个问题,为了保持数据的一致性,究竟需要不需要设计外键呢?

知乎上也有根据这个问题的讨论:

https://www.zhihu.com/question/19600081

不同的人看法也不同。

前辈有说过最好不要加外键,加外键有什么坏处呢?

@ mysqlops

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

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

2.传统行业
1>.软件应用的人数有限,换句话说是可控的;
2>.数据库服务器的数据量也一般不会超大,且活跃数据有限;

综合上述2句话描述,也即数据库服务器的性能不是问题,所以不用过多考虑性能的问题;另外,使用外键可以降低开发成本,借助数据库产品自身的触发器可以实现表与关联表之间的数据一致性和更新;最后一点,使用外键的方式,还可以做到开发人员和数据库设计人员的分工,可以为程序员承担更多的工作量;

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

 

@耗子:不用外键如何保证一致性?自己用触发器或者别的逻辑处理也一样要消耗性能的吧?

@雁南归:虽然都是消耗性能,但是使用触发器和约束消耗的是数据库服务器的性能。如果移到业务逻辑中,消耗的是业务服务器的性能。这就要取舍看性能的瓶颈到底在哪里了。在实际项目中,负责写的主数据库更容易成为性能的瓶颈另一方面业务服务器进行水平拓展一般都比较方便,因此在相当多的情况下,在业务层做约束会比在数据库里面做约束在性能上更划算。 一点浅见。

@梁祎玮:不用外键,不用约束,完全在业务层处理,国内客户需求一天3变,还免费维护的前提下,更改数据库就是灾难。

 

@响马:数据库的诸多设计,帐号,权限,约束,触发器,都是为 C/S 结构设计的,是以 C 端不可信做为假设前提的。B/S 模式安全边界前移到 web 服务层,应用与数据库之间是可信的,应用自行完成这些功能更加灵活。

所以能不用就不用。

@刘勰:响马好霸气的名字。请问如果加外键的话,对于数据检索查询等操作会不会有性能提升?如果外键能不用则不用的话,数据库设计外键的目的是什么?有不得不用外键的情况吗?

 

Young Bean:真搞了笑了,说外键降低数据库性能的,要把外键约束加在业务层里的,有没有想过这样也会降低业务层的性能?业务层里夹带持久层特性,那还要MVC分离做什么?再牛的程序员也不敢说自己对数据库约束关系的掌控能力能超过DBMS的!

jobs:你是真不知道系统的瓶颈往往不在逻辑层而在数据库I/O上还是故意的?

@林灿斌:一般大型系统瓶颈都在数据库的写性能上,这时候如果你加了太多约束,写性能就会快速降低。
而业务层性能可以通过负载均衡快速分摊,数据库读性能也能通过主从分离快速扩展

 

@匿名用户:

建议:一些常量的事情,不经常改的常数,请使用外键,来记录数据关系.而那些经常更改的,请使用更高层的逻辑来记录数据关系.

 

鲍牙叔

非常同意刘鑫的答案。几个月之前,关于要不要建外键我也疑惑过。也遇到了太多人,一上来就说,不要建外键,用业务层保证。

仔细研究了发现,几乎你觉得凡是业务层必须要保证这个约束的,都应该在数据库建立外键。这个约束在数据库里面就一个地方,在业务层可能分散在各个地方。假如你把这个约束当作是一个信息的话,那一个信息最好就放在一个地方。

正确性绝大部分时候比性能重要。我们公司的代码的遗留代码不少没有外键,出现不少脏数据,浪费了很多人力经常清除脏数据。因为业务层的约束是非常不可靠的,业务层天天在变,公司每年都招新人,只要你的代码审查不彻底,随时可能带来脏数据。有时用户的真实数据脏了,你想清理都无法清理。

至于说性能的。说实话,大部分的公司的并发都没有到阿里巴巴,twitter这个水平。一上来就说性能不好的,我只能说你想多了。彩票还没有中,就在想中了以后那么多钱该怎么花。

解决并发的核心,根本不在数据库有多快,而是缓存,使用如静态化,内存缓存,redis,memcache这些缓存。另外还要使用消息队列,将不需要当时反馈给用户的任务排队去做。

假如还没有说服你,你就想想先加再放容易。开始就不加,那你这辈子几乎就没有机会了。

还看到过stackoverflow上面一个精彩的回答说: 外键约束有点像刷牙。妈妈天天跟你说要刷牙刷牙,你可以当耳边风,而且短期也没啥大问题。但是记住,笑的时候要注意了,别露出满口黄牙。以后牙疼也别怪妈妈没有提醒过你。

另外再吐槽一下。很多人不建外键的真实意图就两个字:懒+散。怕外键见了有约束,添加和删除数据有顺序依赖,不方便。喜欢不羁放纵爱自由,从来不带tt, 把别人搞怀孕了就去堕胎,或者拍拍屁股就走了。这种人说用业务层保证,他说用命保证我都不信!

[推荐]
我当时迷惑的时候,看了不少这个帖子上面的回答,包括Fenng的回答: 大家设计数据库时使用外键吗? - MySQL 。里面mysqlops的回答还是很不错的。特别是他的回答有针对互联网和传统企业内的数据库分开分析。

[补充]
在我看来,程序一般是: 正确性>可读性>性能。使用外键约束就是选择了正确性和可读性,不使用,就是选择了性能。你能理解我用Erstudio反向工程打开我们公司的ER图的时候的反应吗?除了后期建的5%的表(Erstudio会自动用线画出外键关系),其他早期建立的每个表都是独立的!!

对于那些用业务层保证的,我也能理解他们的做法。但是我希望说这话的人,是在非常了解数据库的情况下说这句话的。像Fenng以前也说类似的话,我是认可他的做法的,对于阿里巴巴这样的几千几万的服务器来说,炸出10%的性能提升都是值得的,都可以花很大的人力研究如何在业务层能够严谨的保证这个约束。

而且真的有一天性能问题要求你放开外键,也可以分析那几个表是瓶颈,根据2-8原则,只有20%的外键造成了了你80%的性能损耗。你只应该放开这20%的外键,同时要保证这部分的业务层没有错误。

但是往往很多人说这句话的时候,没有考虑到问问题的往往是小白。你说了一句用业务层保证的背后,已经有你对数据库底层的各种思考,但是小白听了就以为是圣旨。我们公司也跟我说“互联网行业一般都不用外键的人“还跟我说过”能用left join就不要用inner join, 因为left join更快"...都是他不知从哪儿听来的。

@ 刘鑫:看应用,用得到就用,用不到不强折腾。外键本身就是个功能而已。想都不想就说外键有害那都是被MySQL社区的一些错误观点给毒害了。

 

 

 

yongzhi :外键是多么好的一个特性啊, 居然不用? 没有外键,表与表之间的关系很不容易搞清楚。
通过中间层去控制数据完整性的过程中难道不需要数据库配合吗? 就不查数据库了?
我认为中间层实现中数据库做的工作量一点不会比数据库外键所需的工作量少,而且中间层实现很容易出现遗漏问题。

至于性能问题,MySQL中外键还好吧, 每个外键自动创建了索引, 死锁问题不大可能出现了,效率也不会差。 不过,对于字典表之类,创建索引就显得多余了。


@月光双刀:楼上各种大神还是没说,如果不用外键,怎么保证数据的一致性= =

 @ ajson:程序控制

Edison Tian:事务

@Ballontt  :数据库的外键一致性性会影响性能,那你在业务中自己写事务逻辑去保证一致性 这不也是开销吗? 这种开销比数据库自己维护的开销小吗?

@Edison Tian 回复Ballontt  :小

@小鱼儿:在并发小的情况下,这种开销应该没什么区别。但是在高并发的情况下,数据库的外键对性能的影响肯定是很高的,而且把数据的一致性完全交给数据库的话,好多东西变得不可控。你自己写代码控制的话,相当于许多数据逻辑自己控制,虽然麻烦,但是出了问题有利于自己查找并针对性解决。

@GuoFu:基本不用。 不使用物理删除,使用标记删除。

@shawshank:标记删除是状态标识吗?这样好吗,数据越来越大,查表起来也不方便,对于一些没必要的数据还是删掉好@GuoFu:是,日志数据删除了,也没有关系。但一般情况是日志直接记在日志文件中,而不是记录到数据库。
业务数据删除的情况应该很少,而且这些数据有他们存在的价值。
删除导致的数据不一致,会给统计分析造成很大的影响, 特别是用户表,订单请求,这样的关键表,如果删除了数据,会导致表连接查询,出现null,从而无法处理数据。 
标记删除会增加程序处理的复杂度,但多做几个项目,就会发现,还是标记删除灵活度大,可以应付各种情况。

@shawshank回复@GuoFu :

说的也是,你遇到数据库设计字段是以json格式存储的吗?你怎么看待这种设计?

@GuoFu:嗯,json格式用的越来越多,最近我做的项目,完全是json+全文索引。没有用关系数据库,以便于支持分布式。开始打算用mongodb,后来了解了一下,它的索引,还有master-slave控制方式,对分布式的支持不太够。后来就用的是bekeleydb的hash数据库做key-json存储,加lucence做全文索引。效果还不错。B系列树,导致的系统瓶颈问题非常突出,以后的他们应该会应用范围越来越小

https://stackoverflow.com/questions/83147/whats-wrong-with-foreign-keys?page=1&tab=active

这个也是相关讨论。

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值