索引
数据库的索引,可以理解成字典的目录,是为了方便数据库快速查询数据用的。
为什么创建索引,查询速度会更快?创建索引的过程,是创建数据结构,提高查询速度。举个例子,如果学生表有100万条输入,如下:
| student_id | student_name |
|---|---|
| 1 | 张三 |
| 2 | 李四 |
| ... | ... |
| 1,000,000 | 王二麻子 |
| 假如我要查询student_name为王二麻子的记录,则数据库需要遍历所有行,即全表查询,最坏情况下要查询100万次才能找到我需要的数据,这样查询速度会很慢。 |
如果创建索引,数据库根据引擎的不同,会通过B+tree(MySQL innnoDB默认)、哈希表等数据结构的方式构建索引。比如用B+tree,要查询student_name为王二麻子的记录,只需要几次就可以查到。
有哪几种索引?
索引类型有主键索引(PRIMARY KEY)、唯一索引(UNIQUE)、普通索引(KEY/VALUE)、全文索引(FULLTEXT)。
- 主键索引(PRIMARY KEY):特殊的唯一索引,一张表只有一个。
- 唯一索引(UNIQUE):索引列值必须唯一。
- 普通索引(KEY/VALUE):最常用的索引,没有约束。
- 全文索引(FULLTEXT):用于全文搜索,适用于文本列(TEXT类长文本)。
当我们在建表时定义好主键,MySQL会自动为主键列创建一个名为PRIMARY的唯一索引;
当我们在创建唯一约束时(约束列的值必须是唯一的),MySQL会自动为该列创建一个唯一索引;
当我们在创建外键约束是(约束列的值必须在被引用的表中存在),MySQL会自动为外键列创建索引(假如还没有索引的话),这是为了确保在更新或删除父表(被引用的表)中的行时,能够快速检查子表(引用表)中是否存在对应的行,从而提高检查的效率。
当然,最常见的是我们自己自定义创建索引,以提高查询效率。
创建索引的目的是为了提高速度,但是创建索引需要额外的资源开销,更新索引也需要时间,因此,创建索引有以下注意事项:
- 数据表记录比较少,不建议创建索引,因为哪怕是遍历查询也很快
- 经常更新的列谨慎创建索引,因为每次更新都需要去更新数据结构,需要消耗计算资源
数据库设计
数据库设计是指设计满足业务需求的数据库表,数据库设计的流程一般是:
- 分析业务需求:根据产品原型、产品文档,分析业务所需要存取的数据
- 数据库概要设计:设计需要创建的数据库、表、字段,绘制数据表关系图
- 创建数据库表:一般通过可视化工具,创建数据库表和字段
为了减少数据冗余、提高数据一致性、避免数据更新异常,数据库设计有三大范式,通常建议数据库设计时遵守。
- 第一范式:确保每一列的原子性。第一范式要求每一列都是不可再分的最小单元。比如某列字段名为学院办公室,存储示例"科技楼102室"。则可以拆分成字段:楼栋("科技楼")、办公室("102室")
- 第二范式:前提必须满足第一范式。第二范式规定数据表中所有非主键必须完全依赖于整个主键,而不能只依赖于主键的一部分。这个范式适用于主键由多个字段组成的情况。如果一个字段只能由部分主键就能决定,则需要拆表。
- 第三范式:前提必须满足第一范式和第二范式。任何非主键字段之间不能有依赖关系,即非主键字段必须直接依赖于主键,而不能通过其他非主键字段间接依赖。
在实际开发过程中,往往需要考虑到满足业务需求的数据存取性能,会违反三大范式。比如:一个学生表和班级表,两者通过class_id做关联,正常设计表如下:
| student_id | student_name | class_id |
|---|---|---|
| 1 | 张三 | NULL |
| 2 | 李四 | 1 |
| 3 | 王五 | 2 |
| 4 | 赵六 | 2 |
| class_id | class_name |
|---|---|
| 1 | 1班 |
| 2 | 2班 |
| 3 | 3班 |
正常情况下,如果要查询学生的所在班级,要通过两个表联表查询。如果业务需求要频繁操作,在数据量比较大时候,可以创建索引提高查询速度。另外,也可以将class_name存储到学生表,这样避免了联表查询操作。显然,这违反了三大范式,这是一种以空间换时间的反范式设计。
| student_id | student_name | class_id | class_name |
|---|---|---|---|
| 1 | 张三 | NULL | NULL |
| 2 | 李四 | 1 | 1班 |
| 3 | 王五 | 2 | 2班 |
| 4 | 赵六 | 2 | 2班 |