NOT NULL、主外键、唯一……MySQL六种约束示例全网最全详解

2023年 7月 11日 63.7k 0

1 alter table emp drop foreign key fk_emp_dept_id;

4、 删除/更新行为

添加了外键之后,在删除父表数据时产生的约束行为,我们就称为删除/更新行为。具体的删除/更新行为有以下几种:

NOT NULL、主外键、唯一......MySQL六种约束示例全网最全详解

在mysql8.0.27版本当中,RESTRICT是默认的删除更新行为!不同的版本可能也会有所差距!

NOT NULL、主外键、唯一......MySQL六种约束示例全网最全详解

具体语法为:

1 ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段) REFERENCES 主表名 (主表字段名) ON UPDATE CASCADE ON DELETE CASCADE;

就是比原先添加外键后面多了这些ON UPDATE CASCADE ON DELETE CASCADE,代表的是更新时采用CASCADE ,删除时也采用CASCADE

5、 演示删除/更新行为

(1)演示RESTRICT

当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有则不允许删除/更新。 (与 NO ACTION 一致) 默认行为

首先要添加外键,默认是RESTRICT行为!

1 alter table emp add constraint fk_emp_dept_id FOREIGN KEY (dept_id) REFERENCES dept(id);

当我要删除父表当中id为5的记录的时候会报错,原因就是emp表的dept_id存在5。假如要更新id也同样会报错的!

NOT NULL、主外键、唯一......MySQL六种约束示例全网最全详解

(2)演示CASCADE

当在父表中删除/更新对应记录时,首先检查该记录是否有对应外键,如果有,则

也删除/更新外键在子表中的记录。

删除外键的语法:

1 ALTER TABLE 表名 DROP FOREIGN KEY 外键约束名;

删除外键的示例:

1 ALTER TABLE emp DROP FOREIGN KEY fk_emp_dept_id;

指定外键的删除更新行为为cascade

1 alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id) on update cascade on delete cascade ;

修改父表id为1的记录,将id修改为6

NOT NULL、主外键、唯一......MySQL六种约束示例全网最全详解

我们发现,原来在子表中dept_id值为1的记录,现在也变为6了,这就是cascade级联的效果。

在一般的业务系统中,不会修改一张表的主键值。

删除父表id为6的记录

NOT NULL、主外键、唯一......MySQL六种约束示例全网最全详解

我们发现,父表的数据删除成功了,但是子表中关联的记录也被级联删除了。

(3)演示SET NULL

当在父表中删除对应记录时,首先检查该记录是否有对应外键,如果有则设置子表中该外键值为null(这就要求该外键允许取null)。

1 alter table emp add constraint fk_emp_dept_id foreign key (dept_id) references dept(id) on update set null on delete set null ;

在进行测试之前,我们先需要删除上面建立的外键 fk_emp_dept_id。然后再通过数据脚本,将emp、dept表的数据恢复了。

接下来,我们删除id为1的数据,看看会发生什么样的现象。

NOT NULL、主外键、唯一......MySQL六种约束示例全网最全详解

我们发现父表的记录是可以正常的删除的,父表的数据删除之后,再打开子表 emp,我们发现子表emp的dept_id字段,原来dept_id为1的数据,现在都被置为NULL了。

NOT NULL、主外键、唯一......MySQL六种约束示例全网最全详解

这就是SET NULL这种删除/更新行为的效果。

四、主键id到底用自增好还是uuid好

在mysql中设计表的时候,mysql官方推荐不要使用uuid或者不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那么为什么不建议采用uuid,使用uuid究竟有什么坏处?

1、测试uuid和自增id还有随机数插入效率

首先来建立三张表,user_auto_key代表的是自增表,user_uuid代表的是id存储的uuid,random_key代表的是表id是雪花id。然后通过连接jdbc批量插入数据测试测试结果如下:

NOT NULL、主外键、唯一......MySQL六种约束示例全网最全详解

在已有数据量为130W的时候:我们再来测试一下插入10w数据,看看会有什么结果:

NOT NULL、主外键、唯一......MySQL六种约束示例全网最全详解

可以看出在数据量100W左右的时候,uuid的插入效率垫底,并且在后序增加了130W的数据,uudi的时间又直线下降。时间占用量总体可以打出的效率排名为:auto_key>random_key>uuid,uuid的效率最低

2、使用自增id的缺点

1.别人一旦爬取你的数据库,就可以根据数据库的自增id获取到你的业务增长信息,很容易分析出你的经营情况

2.对于高并发的负载,innodb在按主键进行插入的时候会造成明显的锁争用,主键的上界会成为争抢的热点,因为所有的插入都发生在这里,并发插入会导致间隙锁竞争

3.Auto_Increment锁机制会造成自增锁的抢夺,有一定的性能损失

4.自增id涉及到数据迁移的话是相当麻烦的!

5.而且一旦涉及到分库分表自增id也是相当麻烦的!

3、使用uuid的缺点

因为uuid相对顺序的自增id来说是毫无规律可言的,新行的值不一定要比之前的主键的值要大,所以innodb无法做到总是把新行插入到索引的最后,而是需要为新行寻找新的合适的位置从而来分配新的空间。这个过程需要做很多额外的操作,数据的毫无顺序会导致数据分布散乱,将会导致以下的问题:

1.写入的目标页很可能已经刷新到磁盘上并且从缓存上移除,或者还没有被加载到缓存中,innodb在插入之前不得不先找到并从磁盘读取目标页到内存中,这将导致大量的随机IO。

2.因为写入是乱序的,innodb不得不频繁的做页分裂操作,以便为新的行分配空间,页分裂导致移动大量的数据,一次插入最少需要修改三个页以上

3.由于频繁的页分裂,页会变得稀疏并被不规则的填充,最终会导致数据会有碎片

页分裂和碎片问题,uuid确实会引起这个问题,但雪花可以解决这个问题,雪花算法天然具有顺序性新插入的ID一定是最大的,所以我认为用雪花算法是一个很不错的选择!

五、实际开发尽量少用外键

主键和索引是不可少的,不仅可以优化数据检索速度,开发人员还省不其它的工作。

矛盾焦点:数据库设计是否需要外键。这里有两个问题:

一个是如何保证数据库数据的完整性和一致性;

二是第一条对性能的影响。

这里分为了正方和反方两个观点,供参考!

1、正方观点

1.由数据库自身保证数据一致性,完整性,更可靠,因为程序很难100%保证数据的完整性,而用外键即使在数据库服务器当机或者出现其他问题的时候,也能够最大限度的保证数据的一致性和完整性。

2.有主外键的数据库设计可以增加ER图的可读性,这点在数据库设计时非常重要。

3.外键在一定程度上说明的业务逻辑,会使设计周到具体全面。

数据库和应用是一对多的关系,A应用会维护他那部分数据的完整性,系统一变大时,增加了B应用,A和B两个应用也许是不同的开发团队来做的。他们如何协调保证数据的完整性,而且一年以后如果又增加了C应用呢?

2、反方观点

1.可以用触发器或应用程序保证数据的完整性

2.过分强调或者说使用主键/外键会平添开发难度,导致表过多等问题

3.不用外键时数据管理简单,操作方便,性能高(导入导出等操作,在insert, update, delete 数据的时候更快)

在海量的数据库中想都不要去想外键,试想,一个程序每天要insert数百万条记录,当存在外键约束的时候,每次要去扫描此记录是否合格,一般还不 止一个字段有外键,这样扫描的数量是成级数的增长!我的一个程序入库在3个小时做完,如果加上外键,需要28个小时!

3、结论

1.在大型系统中(性能要求不高,安全要求高),使用外键;在大型系统中(性能要求高,安全自己控制),不用外键;小系统随便,最好用外键。

2.用外键要适当,不能过分追求

3.不用外键而用程序控制数据一致性和完整性时,应该写一层来保证,然后个个应用通过这个层来访问数据库。

需要注意的是:

MySQL允许使用外键,但是为了完整性检验的目的,在除了InnoDB表类型之外的所有表类型中都忽略了这个功能。这可能有些怪异,实际上却非常正常:对于数据库的所有外键的每次插入、更新和删除后,进行完整性检查是一个耗费时间和资源的过程,它可能影响性能,特别是当处理复杂的或者是缠绕的连接数时。因而,用户可以在表的基础上,选择适合于特定需求的。

所以,如果需要更好的性能,并且不需要完整性检查,可以选择使用MyISAM表类型,如果想要在MySQL中根据参照完整性来建立表并且希望在此基础上保持良好的性能,最好选择表结构为innoDB类型。

相关文章

Oracle如何使用授予和撤销权限的语法和示例
Awesome Project: 探索 MatrixOrigin 云原生分布式数据库
下载丨66页PDF,云和恩墨技术通讯(2024年7月刊)
社区版oceanbase安装
Oracle 导出CSV工具-sqluldr2
ETL数据集成丨快速将MySQL数据迁移至Doris数据库

发布评论