【禁用外键】为什么互联网大厂禁用外键约束?详谈外键的优缺点和使用场景

2023-10-27

导航:

【Java笔记+踩坑汇总】Java基础+进阶+JavaWeb+SSM+SpringBoot+瑞吉外卖+SpringCloud+黑马旅游+谷粒商城+学成在线+MySQL高级篇+设计模式+常见面试题+源码

目录

一、外键介绍

1.1 概述 

1.2 练习

1.2.1 数据准备

1.2.2 验证有外键时,删除记录要维护外键

1.2.3 重新添加外键

1.2.4 查询所有外键

二、外键的优缺点 

2.1 外键缺点

2.2 外键优点

三、适用场景

3.1 哪些情况下不要用外键?为什么互联网大厂禁用外键约束?

3.2 哪些情况下可以用外键?


一、外键介绍

1.1 概述 

-- 创建表时添加外键约束
CREATE TABLE 表名(
   列名 数据类型,
   …
   [CONSTRAINT] [外键取名名称] FOREIGN KEY(外键列名) REFERENCES 主表(主表列名) 
); 

-- 创建表时添加外键约束,constraint译作限制,束缚;references译作关联,参考,提及
create table 表名(
   列名 数据类型,
   …
   [constraint] [外键取名名称] foreign key(外键列名) references 主表(主表列名) 
); 
-- 建完表后添加外键约束
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名称) REFERENCES 主表名称(主表列名称);

-- 建完表后添加外键约束
alter table 表名 add constraint 外键名称 foreign key (外键字段名称) references 主表名称(主表列名称);
  • 删除外键约束

ALTER TABLE 表名 DROP FOREIGN KEY 外键名称;

1.2 练习

1.2.1 数据准备

-- 删除表
DROP TABLE IF EXISTS emp;
DROP TABLE IF EXISTS dept;

-- 部门表
CREATE TABLE dept(
	id int primary key auto_increment,
	dep_name varchar(20),
	addr varchar(20)
);
-- 员工表 
CREATE TABLE emp(
	id int primary key auto_increment,
	name varchar(20),
	age int,
	dep_id int,

	-- 添加外键 dep_id,关联 dept 表的id主键
	CONSTRAINT fk_emp_dept FOREIGN KEY(dep_id) REFERENCES dept(id)	
);

添加数据

-- 添加 2 个部门
insert into dept(dep_name,addr) values
('研发部','广州'),('销售部', '深圳');
​
-- 添加员工,dep_id 表示员工所在的部门
INSERT INTO emp (name, age, dep_id) VALUES 
('张三', 20, 1),
('李四', 20, 1),
('王五', 20, 1),
('赵六', 20, 2),
('孙七', 22, 2),
('周八', 18, 2);

 

 

1.2.2 验证有外键时,删除记录要维护外键

此时删除 研发部 这条数据,会发现无法删除。

DELETE FROM dept WHERE id=1

 

1.2.3 验证没外键时,删除记录无需维护外键  

删除外键

alter table emp drop FOREIGN key fk_emp_dept;

此时删除 研发部 这条数据,会发现删除成功:

DELETE FROM dept WHERE id=1

 

 

 

 

1.2.3 重新添加外键

alter table emp add CONSTRAINT fk_emp_dept FOREIGN key(dep_id) REFERENCES dept(id);

1.2.4 查询所有外键

SELECT 
  COLUMN_NAME, 
  CONSTRAINT_NAME, 
  REFERENCED_TABLE_NAME, 
  REFERENCED_COLUMN_NAME 
FROM 
  INFORMATION_SCHEMA.KEY_COLUMN_USAGE 
WHERE 
  TABLE_NAME = 'emp' 
  AND REFERENCED_TABLE_NAME IS NOT NULL;

 

 

二、外键的优缺点 

2.1 外键缺点

  • 改、删时要考虑外键:每次做DELETE 或者UPDATE都必须考虑外键约束,不方便。
  • 表级锁导致并发差:并发问题外键约束会启用行级锁主表写入时会进入阻塞
  • 级联删除问题:删除主表的一条记录,该记录外键关联的从表记录也会随之删除,导致数据不可控。例如删除“订单表”的一条订单,关联的“订单详情表”的一条记录也会随之删除。
  • 耦合高、迁移麻烦:主表从表之间互相耦合,主表数据量过大要分表并迁移数据时,就必须先删除外键,不然你刚删完主表的一条记录,从表关联记录也级联删除了,导致数据丢失。

2.2 外键优点

  • 数据一致性:数据库通过外键可以保证数据的完整性和一致性。因为在更新主表记录时,从表对应的记录也会随之更改,并且更改时会加表级锁,以牺牲并发性为代价,保证数据的一致性。例如删除“订单表”的一条订单,关联的“订单详情表”的一条记录也会随之删除。
  • 增加ER图的可读性:通过外键,可以更直观的看出表与表之间的关系。

三、适用场景

3.1 哪些情况下不要用外键?为什么互联网大厂禁用外键约束?

综合对比外键的优缺点,可以得出结论:

并发量高、表数据量大的分布式项目适合使用外键。防止每次更新数据时都要加表级锁,维护外键的一致性。

因为互联网大厂的产品并发量高,并且一般是分布式项目,为了提高数据库的并发性能,一般都禁用外键,在业务层面实现数据一致性,例如删除“订单表”一条记录前,先关联查询“订单详情表”的对应记录,然后先后一起删除。

3.2 哪些情况下可以用外键?

综合对比外键的优缺点,可以得出结论:

并发量不高、表数据量不大、对数据一致性要求较高的单体式项目适合使用外键。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【禁用外键】为什么互联网大厂禁用外键约束?详谈外键的优缺点和使用场景 的相关文章

  • 如何从shell脚本自动登录MySQL?

    我有一个 MySQL 服务器 其中有一个用户和密码 我想在 shell 脚本中执行一些 SQL 查询而不指定密码 如下所示 config sh MYSQL ROOT root MYSQL PASS password mysql sh sou
  • 显示标准化数据

    跟进问题 添加 2 个不同表的总和 https stackoverflow com questions 39717541 adding sum from 2 different tables 我创建了3个表 members videos v
  • Galera 集群问题

    我想在我们的生产环境中使用Galera集群 但我有一些顾虑 每个表必须至少定义一个显式主键 每个表必须运行在InnoDB或XtraDB存储引擎下 分批处理您的大额交易 例如 不要让一个事务插入 100 000 行 而是将其分成更小的块 例如
  • 在 C# 中,当有人插入、删除或修改记录时,如何从 MySQL 获取事件?

    我正在 WPF Net 中开发一个程序 我需要知道何时有人对数据库的任何表进行更改 这个想法是在数据库发生更改时从数据库接收一个事件 我读了很多文章 但找不到解决我的问题的方法 亲切的问候 最好的解决方案是使用消息队列 在您的应用程序向数据
  • 如何在mysql中选择具有相同值集的列?

    我的桌子是 patients pid name city disease did dname has disease did pid 我想列出具有相同疾病组的患者 pid 和 did 分别是患者和疾病表中的主键 并且是 has diseas
  • 连接 Netbeans 和 MySQL 但出现大整数错误

    所以我正在尝试向我的 Netbeans 数据库 即 MySQL 添加新连接 但我遇到了大整数转换错误 有人可以帮助我吗 详细地 我右键单击现有的MySQL 服务器位于 localhost 3306 root 已断开连接 gt gt 选择co
  • MySql 5.7 ORDER BY 子句不在 GROUP BY 子句中并且包含非聚合列

    我试图在不禁用 my ini 中的 only full group by 的情况下弄清楚 这是我的查询 SELECT p title COUNT t qty AS total FROM payments t LEFT JOIN produc
  • MySQL 8 用逗号分割字符串并将其转换为JSON ARRAY

    我有以下字符串 a b c d 我想将它转换成一个 json 数组 像这样 a b c d MySQL 8 有什么函数可以实现这个功能吗 Try SELECT CAST CONCAT REPLACE a b c d AS JSON See
  • 合并两个 MYSQL SELECT 查询[重复]

    这个问题在这里已经有答案了 可能的重复 如何将两个 Post Category 表 MYSQL SELECT 查询合并为一个 https stackoverflow com questions 12972130 how to combine
  • 即使没有结果也返回一个值

    我有这种简单的查询 它返回给定 id 的非空整数字段 SELECT field1 FROM table WHERE id 123 LIMIT 1 问题是如果找不到 id 结果集就是空的 我需要查询始终返回一个值 即使没有结果 我有这个东西工
  • 使用Perl/DBI/MySQL/InnoDB查找外键信息

    我想以编程方式查找 MySQL 数据库中特定 InnoDB 表的外键 我正在使用 Perl 我偶然发现 dbh gt foreign key info 我刚刚尝试使用它 但似乎有点错误 它不会返回 ON DELETE 和 ON UPDATE
  • MySQL 排序顺序 - 排序规则?

    我在对 MySQL 中的 char 字段进行排序时遇到困难 问题是重音字符与非重音字符混淆 例如 Abc bd Acc 我认为这可能与整理有关 所以我将表格的排序规则更改为utf8 ut8 bin 看完之后这个帖子 https stacko
  • MaxListenersExceededWarning:检测到可能的 EventEmitter 内存泄漏。添加了 11 条消息列表。使用emitter.setMaxListeners()来增加限制

    我知道这可能会标记为重复的解决方案 但堆栈溢出的解决方案对我不起作用 Problem node 5716 MaxListenersExceededWarning Possible EventEmitter memory leak detec
  • 删除行导致锁超时

    当我尝试从表中删除行时 我不断收到这些错误 这里的特殊情况是我可能同时运行5个进程 该表本身是一个 Innodb 表 约有 450 万行 我的 WHERE 子句中使用的列没有索引 其他指数按预期运行 这是在事务中完成的 首先删除记录 然后插
  • MYSQL - 使用逗号分隔字符串作为变量输入的存储过程

    我希望有人能够提供帮助 我已经创建了我的第一个存储过程 没什么花哨的 但是我遇到了问题 我想给它一个字符串输入 例如 1 2 3 4 5 然后它执行一个简单的操作SELECT FROM TABLE WHERE EAN IN VAR 所以存储
  • MYSQL从每个类别中随机选择一条记录

    我有一个数据库Items表看起来像这样 id name category int 有几十万条记录 每个item可以是 7 种不同的之一categories 对应于categories table id category 我想要一个从每个类别
  • 学说迁移后备

    我们正在使用原则迁移 当迁移包含多个操作并且其中一个操作失败时 通常会出现问题 例如 如果迁移添加了 5 个外键 其中第 5 个失败 而字段长度不同 则修复字段错误并重新生成迁移不会not修复整个问题 而现在出现一个与 4 个密钥已存在有关
  • 随机组合 MySQL 数据库中的两个单词

    我有一个包含名词和形容词的数据库 例如 id type word 1 noun apple 2 noun ball 3 adj clammy 4 noun keyboard 5 adj bloody ect 我想创建一个查询 它将抓取 10
  • 通过触发器应用表的列权限

    现在 我有一个名为 Members 的表 其中包含内容 分为联系人数据 银行数据 现在 管理员应该能够创建 更新 删除用户 这些用户保存在另一个表中 该表只能访问管理员 用户应该获得自己的 mysql 用户帐户 管理员还应该能够设置权限 例
  • 内部 while 循环不工作

    这是我项目网页上的代码片段 这里我想显示用户选择的类别 然后想显示属于该类别的主题 在那里 用户可以拥有多个类别 这没有问题 我可以在第一个 while 循环中打印所有这些类别 问题是当我尝试打印主题时 结果只显示一行 但每个类别中有更多主

随机推荐