前言
问: 约束存在的意义是什么?
答:为防止错误的数据被插入到数据表,MySQL中定义了一些维护数据库完整性的规则;这些规则常称为表的约束 是对数据准确性的一种提前控制
例如:人员的姓名不能为空,人的年龄只能在0~150岁之间。约束可以对数据库中的数据进行保护。
约束可以在建表的时候直接声明,也可以为已建好的表添加约束。
正文
我们简单说一下约束的几种类型和使用方法
主键约束
主键约束理念
这个算是我们最常使用的 我们在创建表的时候一般会选用ID做主键约束 主键约束用于唯一的标识表中的每一行。被标识为主键的数据在表中是唯一的且其值不能为空。这点类似于我们每个人都有一个身份证号,并且这个身份证号唯一,也就是我们的ID 全部都是不能重复 也就衍生出很多 主键的生成策略 UUID 雪花算法等等
提出问题
问:
如果我们在创建的时候没有去主动设置一个主键约束怎么办?MySQL数据表使用InnoDB作为存储引擎的时候,数据结构就是使用B+树,而数据本身存储在主键索引上,也就是通常所说的聚簇索引,也就是每个表都需要有个聚簇索引树,但是,在建表的时候却发现可以不用指定主键,那么MySQL对于没有指定主键的表示如何处理的呢?
回答:
既然InnoDB对数据的存储必须依赖于主键,那么对于没有创建主键的表,该怎么办?
InnoDB对聚簇索引处理如下:
- 如果定义了主键,那么InnoDB会使用主键作为聚簇索引
- 如果没有定义主键,那么会使用第一非空的唯一索引(NOT NULL and UNIQUE INDEX)作为聚簇索引
- 如果既没有主键也找不到合适的非空索引,InnoDB会自动帮你创建一个不可见的、长度为6字节的row_id,而且InnoDB 维护了一个全局的 dictsys.row_id,所以未定义主键的表都共享该row_id,每次插入一条数据,都把全局row_id当成主键id,然后全局row_id加1
很明显,缺少主键的表,InnoDB会内置一列用于聚簇索引来组织数据
。而没有建立主键的话就没法通过主键来进行索引,查询的时候都是全表扫描,小数据量没问题,大数据量就会出现性能问题。
但是,问题真的只是查询影响吗?不是的,对于生成的ROW_ID,其自增的实现来源于一个全局的序列,而所以有ROW_ID的表共享该序列,这也意味着插入的时候生成需要共享一个序列,那么高并发插入的时候为了保持唯一性就避免不了锁的竞争,进而影响性能。
即便我们没有去主动创建一个主键约束 MySQL 数据库也会创建帮我们去创建一个
小总结
-
如果定义了主键,那么InnoDB会使用主键作为聚簇索引
-
如果没有定义主键,那么会使用第一非空的唯一索引(NOT NULL and UNIQUE INDEX)作为聚簇索引
-
如果既没有主键也找不到合适的非空索引,那么InnoDB会自动生成一个不可见的名为row_id的列名为GEN_CLUST_INDEX的聚簇索引,该列是一个6字节的自增数值,随着插入而自增–补充:该全局row_id在代码实现上使用的是bigint unsigned类型,但实际上只给row_id留了6字节,这种设计就会存在一个问题:如果全局row_id一直涨,一直涨,直到2的48幂次-1时,这个时候再+1,row_id的低48位都为0,结果在插入新一行数据时,拿到的row_id就为0&