zoukankan      html  css  js  c++  java
  • 为什么大多数互联网公司不用外键约束

    是否使用外键约束

    【强制】不得使用外键与级联,一切外键概念必须在应用层解决.-《阿里Java规范》

    首先外键(Foreign Key)是什么东西

    使用方案

    假设有一个score表 id是自增id,score是分数,student_id是学号。

    另一个student表,id是自增id,name是名字,student_id是学号。

    那么设计这个的时候就希望有一个关联关系,让score的student_id指向student表的student_id,存在一个学生对应多个成绩的关系。所以我可以使用以下SQL语句

    ALTER TABLE score
    ADD CONSTRAINT FOREIGN KEY (student_id)
    REFERENCES student(student_id);
    

    创建一个外键索引完成这个规则

    完成后的表关系如下

    外键原理

    被指向的字段,具有唯一性

    可以保证成绩字段的一致性,即每一次插入一个score数据,首先要检测是否student表存在这个id,保证一致性

    如果在外键类型上使用CASCADE,则会保证在做更新和删除sutudent表的student_id时,触发一次级联操作,会同步更新score表的student_id或者删除student_id.

    外键类型RESTRICT 也同样会做一次检测,但不会做级联操作,而是直接拒绝操作。

    场景思考

    知道外键是什么后,我们来思考一个场景:

    现在有一个电商系统,用户有一个账户id,商品有一个商品id,这两个字段和订单绑定,此时订单id和账户表ID构成一个外键关系,同时和商品表id也构成一个外键关系,那么我每次生成一笔订单,就需要向另外两张表查询检测一次数据,那么就存在几个问题:

    • 增删改触发这个查询操作的性能消耗,服务器系统是否允许
    • 在其他表查询会上需要对其他表做一个内部锁,是否存在高并发死锁情况
    • 数据一致性全部交给数据库服务器,数据库服务器是否能够承受

    这些问题在互联网公司会显得格外严重,因为访问流量大的时候以上问题基本上是完全无法得到MySQL系统本身解决的

    同时在做分库分表设计的时候,外键约束就会显得格外离谱。

    同时MySQL系统的外键设计是背离部分SQL标准的

    引用自博客园Eden: (https://www.cnblogs.com/discuss/articles/1862244.html)

    对SQL标准的背离:如果ON UPDATE CASCADE或ON UPDATE SET NULL递归更新相同的表,之前在级联过程中该表一被更新过,它就象RESTRICT一样动作。这意味着你不能使用自引用ON UPDATE CASCADE或者ON UPDATE SET NULL操作。这将阻止级联更新导致的无限循环。另一方面,一个自引用的ON DELETE SET NULL是有可能的,就像一个自引用ON DELETE CASCADE一样。级联操作不可以被嵌套超过15层深。

    对SQL标准的背离: 类似一般的MySQL,在一个插入,删除或更新许多行的SQL语句内,InnoDB逐行检查UNIQUE和FOREIGN KEY约束。按照SQL的标准,默认的行为应被延迟检查,即约束仅在整个SQL语句被处理之后才被检查。直到InnoDB实现延迟的约束检查之前,一些事情是不可能的,比如删除一个通过外键参考到自身的记录。

    处理

    因为以上问题,我们通常在建模时隐性设计外键约束,实际实现采用业务逻辑模拟外键的方式处理,这样可以解决把一致性全部放在DBA上的性能问题,同时我们可以采用允许脏数据存在,然后定时数据清理的方案去保证数据处理的分时性能,避免高峰处理。

    这样的好处:

    • 解决性能问题
    • 增加了可扩展性,框架迁移不用在数据库系统内部实现逻辑约束
    • 分库分表的时候方便
    • 不会在DB层面造成死锁

    反推:是否可以使用外键约束

    我觉得在部分业务场景下是可以考虑使用的,回到最开始的例子,教务系统的成绩模块重要的点不再是性能问题,而是高可靠,因为对学校来说,系统存在以下特点:

    • 数据量较少,一个学校学生最多不超过10万人,通常在5000-50000这个区间内,对DB来说这是一个很小的数据量
    • 数据不容许出错,因为成绩和学生的人身利益直接挂钩
    • 能够进行数据修改操作的用户极少,只有教务处录入成绩的老师。
    • 如果放在业务部分,如果出现student表student_id在第一次被删除后,未清理score表数据,这个student_id短时间内被再次使用,而没有做数据清理,就容易出现成绩复用错误,诸如此类

    所以 不得使用外键与级联,一切外键概念必须在应用层解决。 大部分情况下正确,但同样我认为需要分业务场景解决,并不能一竿子打死。

    %1
  • 相关阅读:
    uni-app中动态设置头部颜色及字体
    微信小程序中 showToast 真机下一闪而过相关问题
    uni-app踩坑记
    配置git提交规范跟规范校验(ESLint、commitLint、husky)
    vscode中配置git终端
    vue插槽学习之——作用域插槽
    布局小技巧集合之——动态列表固定列数固定间距自适应布局
    写入自定义 ASP.NET Core 中间件
    [转]NET实现RSA AES DES 字符串 加密解密以及SHA1 MD5加密
    JavaScript事件循环机制
  • 原文地址:https://www.cnblogs.com/JethroYu/p/13570630.html
Copyright © 2011-2022 走看看