索引(index)
什么是索引
索引就相当于一本书的目录,通过目录可以快速的找到对应的资源。
在数据库方面,查询一张表的时候有两种检索方式:
- 全表扫描
- 根据索引检索,效率很高(最根本的原理是缩小了扫描的范围)
索引虽然可以提高检索效率,但是不能随意的添加索引,因为索引也是数据库当中的对象,也需要数据库不断的维护。是有维护成本的。
比如,表中的数据经常被修改,这样就不适合添加索引,因为数据一旦修改,索引需要重新排序(主要),进行维护。
例如:
select ename,sal from emp where ename = 'SMITH';
当ename字段上没有添加索引的时候,以上sql语句会进行全表扫描,扫描ename字段中所有的值。
当ename字段上添加索引的时候,以上sql语句会根据索引扫描,快速定位。
何时添加索引(条件)
- 数据量庞大(根据客户的需求,根据线上的环境)
- 该字段很少的DML操作(因为字段进行修改操作,索引也需要维护)
- 该字段经常出现在where子句中(经常根据哪个字段查询)
注意:主键和具有unique约束的字段自动会添加索引。因此,根据主键查询效率较高,尽量根据主键检索。
SQL语句的执行计划
mysql> explain select ename,sal from emp where sal = 5000;
+—-+———–+——-+——+————-+——+———+——+——+———–+
|id |select_type |table |type| possible_keys |key |key_len |ref |rows|Extra |
+—-+———–+——-+——+————-+——+———+——+——+———–+
|1 | SIMPLE | emp |ALL| NULL| NULL | NULL| NULL |14| Using where |
+—-+———–+——-+——+————-+——+———+——+——+———–+
给薪资sal字段添加索引:
create index emp_sal_index on emp(sal);
+—-+———–+——-+——+————-+————-+———+——-+——+———–+
|id |select_type|table|type| possible_keys| key| key_len| ref |rows| Extra|
+—-+———–+——-+——+————-+————-+———+——-+——+———–+
|1 |SIMPLE |emp |ref|emp_sal_index |emp_sal_index | 9| const |1|Using where|
+—-+———–+——-+——+————-+————-+———+——-+——+———–+
索引底层原理
索引底层采用的数据结构是:B + Tree
通过B Tree缩小扫描范围,底层索引进行了排序,分区,索引会携带数据在表中的“物理地址”,最终通过索引检索到数据之后,获取到关联的物理地址,通过物理地址定位表中的数据,效率是最高的。
select ename from emp where ename = ‘SMITH’;
通过索引转换为:
select ename from emp where 物理地址 = 0x3;
索引分类
- 单一索引:给单个字段添加索引
- 复合索引: 给多个字段联合起来添加1个索引
- 主键索引:主键上会自动添加索引
- 唯一索引:有unique约束的字段上会自动添加索引
- ……
索引失效
select ename from emp where ename like '%A%';
模糊查询的时候,第一个通配符使用的是%,这个时候索引是失效的。
参考文章
索引详解,请参考:最全面的MySQL索引详解
视图(view)
什么是视图
虚拟的表,和普通表一样使用,只是站在不同的角度去看到数据。(同一张表的数据,通过不同的角度去看待)
应用场景
- 多个地方用到同样地查询结果
- 该查询结果使用的SQL语句较复杂
怎么创建 / 删除视图
create view myview as select empno,ename from emp;
drop view myview;
注意:只有DQL语句才能以视图对象的方式创建出来。
面向视图操作
对视图进行增删改查,会影响到原表数据。(通过视图影响原表数据的,不是直接操作的原表),可以对视图进行CRUD操作。
mysql> select * from myview;
+——-+——–+
| empno | ename |
+——-+——–+
| 7369 | SMITH |
| 7499 | ALLEN |
| 7521 | WARD |
| 7566 | JONES |
| 7654 | MARTIN |
| 7698 | BLAKE |
| 7782 | CLARK |
| 7788 | SCOTT |
| 7839 | KING |
| 7844 | TURNER |
| 7876 | ADAMS |
| 7900 | JAMES |
| 7902 | FORD |
| 7934 | MILLER |
+——-+——–+
create table emp_bak as select * from emp;
create view myview1 as select empno,ename,sal from emp_bak;
update myview1 set ename='hehe',sal=1 where empno = 7369; /*通过视图修改原表数据*/
delete from myview1 where empno = 7369; /*通过视图删除原表数据*/
视图的作用
视图可以隐藏表的实现细节。保密级别较高的系统,数据库只对外提供相关的视图,java程序员只对视图对象进行CRUD。
数据库三范式(重点,面试常问)
什么是设计范式
设计表的依据。按照这个三范式设计的表不会出现数据冗余。
规范化
一个低一级的关系模式通过模式分解可以转化为若干个高一级范式的关系模式的集合,这个过程叫做规范化。
三范式有哪些
- 第一范式( 最低要求 )
- 第二范式
- 第三范式
第一范式(1NF)
任何一张表都应该有主键,并且每一个字段原子性不可再分。
上述句子,强调的是列的原子性,即列不能够在分成其它几列。
说明:在任何一个关系数据库中,第一范式(1NF)是对关系模式的设计基本要求,一般设计中都必须满足第一范式(1NF)。不过有些关系模型中突破了1NF的限制,这种称为非1NF的关系模型。换句话说,是否必须满足1NF的最低要求,主要依赖于所使用的关系模型。
示例1:(以下不符合第一范式)
学生编号 | 学生姓名 | 联系方式 |
---|---|---|
1001 | 张三 | zs@gmail.com,1371234567 |
1002 | 李四 | ls@qq.com,1381234567 |
1003 | 王五 | ww@163.com,1391234567 |
出现的问题:
- 没有主键
- 联系方式还可以拆成两个字段
修改后:
学生编号 | 学生姓名 | phone | |
---|---|---|---|
1001 | 张三 | zs@gmail.com | 1371234567 |
1002 | 李四 | ls@qq.com | 1381234567 |
1003 | 王五 | ww@163.com | 1391234567 |
关于第一范式,每一行必须是唯一的,也就是每个表必须有主键,这是我们数据库设计的最基本的要求,主要通常采用数值型或定长字符串表示。关于列不可再分,应该根据具体的情况来决定,如联系方式,为了开发上的便利,行可能就采用一个字段。
第二范式(2NF)
定义: 若某关系R属于第一范式,且每一个非主属性完全函数依赖于任何一个候选码,则关系R属于第二范式。
首先是1NF,即建立在第一范式的基础之上,其次,表必须有一个主键,最后,所有非主键字段必须完全依赖主键,不能产生部分依赖(即不能只依赖于主键的一部分)。
候选码
若关系中的某一属性组的值能唯一地标识一个元组,而其子集不能,则称该属性组为候选码。若一个关系中有多个候选码,则选定其中一个为主码。主属性
所有候选码的属性称为主属性。不包含在任何候选码中的属性称为非主属性或非码属性。函数依赖
设R(U)是属性集U上的关系模式,X、Y是U的子集。若对于R(U)的任意一个可能的关系r,r中不可能存在两个元组在X上的属性值相等,而在Y上的属性值不等,则称Y函数依赖于X或X函数确定Y。完全函数依赖
设R(U)是属性集U上的关系模式,X、Y是U的子集。如果Y函数依赖于X,且对于X的任何一个真子集X’,都有Y不函数依赖于X’,则称Y对X完全函数依赖。记作:如果Y函数依赖于X,但Y不完全函数依赖于X,则称Y对X部分函数依赖。
理解: 第二范式是指每个表必须有一个(有且仅有一个)数据项作为关键字或主键(primary key),其他数据项与关键字或者主键一一对应,即其他数据项完全依赖于关键字或主键。由此可知单主属性的关系均属于第二范式。
判断一个关系是否属于第二范式:
- 找出数据表中的所有码
- 找出所有主属性和非主属性
- 判断所有的非主属性对码的部分函数依赖
示例2:
学生编号 | 学生姓名 | 教师编号 | 教师姓名 |
---|---|---|---|
1001 | 张三 | 001 | 王老师 |
1002 | 李四 | 002 | 赵老师 |
1003 | 王五 | 001 | 王老师 |
1001 | 张三 | 002 | 赵老师 |
出现的问题:
- 没有主键,不符合第一范式
示例3:
学生编号(PK) | 学生姓名 | 教师编号(PK) | 教师姓名 |
---|---|---|---|
1001 | 张三 | 001 | 王老师 |
1002 | 李四 | 002 | 赵老师 |
1003 | 王五 | 001 | 王老师 |
1001 | 张三 | 002 | 赵老师 |
出现的问题:
- 示例3虽确定了主键,但此表会表现出大量的冗余,主要涉及到的冗余字段为“学生姓名”和“教师姓名”,出现冗余的原因在于,学生姓名部分依赖于主键的一个字段:学生编号,而没有依赖教师编号,而教师姓名部分依赖主键的一个字段:教师编号,这就是第二范式所说的部分依赖。
解决办法:
多对多,三张表,关系表两个外键。
示例4:
t_stu 学生表:
stu_no | stu_name |
---|---|
1 | 张三 |
2 | 李四 |
3 | 王五 |
t_tea 教师表:
tea_no | tea_name |
---|---|
1 | 王老师 |
2 | 张老师 |
3 | 李老师 |
t_stu_tea 学生教师关系表:
id(PK) | stu_no(FK) | tea_no(FK) |
---|---|---|
1 | 1 | 3 |
2 | 1 | 1 |
3 | 2 | 2 |
4 | 2 | 3 |
5 | 3 | 1 |
6 | 3 | 3 |
示例5(示例3修改):
说明: 第二范式(2NF)要求实体的属性完全依赖于主键。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主键的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。简而言之,第二范式就是在第一范式的基础上属性完全依赖于主键。
第三范式
建立在第二范式的基础之上,所有非主键字段直接依赖主键,不能产生传递依赖。
传递函数依赖
第三范式(3NF)是第二范式(2NF)的一个子集,即满足第三范式(3NF)必须满足第二范式(2NF)。
首先是 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。
示例6:
从上表可以看出,班级名称字段存在冗余,因为班级名称字段没有直接依赖于主键,班级名称字段依赖于班级编号,班级编号依赖于学生编号,那么这就是传递依赖。
示例7(示例6修改): 将冗余字段单独拿出来建立表
以上设计是一种典型的一对多的设计,一存储在一张表中,多存储在一张表中,在多的那张表中添加外键指向一的一方的主键
一对多,两张表,多的表加外键。
示例8:
t_class 班级表:
cla_no(PK) | cla_name |
---|---|
1 | 班级1 |
2 | 班级2 |
t_stu 学生表:
stu_no(PK) | stu_name | cla_no(FK) |
---|---|---|
101 | 张1 | 1 |
102 | 张2 | 1 |
103 | 张3 | 2 |
104 | 张4 | 2 |
105 | 张5 | 2 |
三范式总结
- 第一范式:有主键,具有原子性,字段不可分割
- 第二范式:完全依赖,没有部分依赖
- 第三范式:没有传递依赖
数据库设计尽量遵循三范式,但是还是根据实际情况进行取舍,有时可能会拿冗余换速度,最终用目的要满足客户需求。
三范式更多详情,请点击:数据库(第一范式,第二范式,第三范式)
其他范式
目前,关系数据库有六种范式,除了上述的三种范式,还有: 巴斯-科德范式(BCNF) 、 第四范式(4NF)和第五范式(5NF,又称完美范式)。
BC范式 BCFN
定义: 关系模式R<U,F>中,若每一个决定因素都包含码,则R<U,F>属于BCFN。
理解: 根据定义我们可以得到结论,一个满足BC范式的关系模式有:
- 所有非主属性对每一个码都是完全函数依赖
- 所有主属性对每一个不包含它的码也是完全函数依赖
- 没有任何属性完全函数依赖于非码的任何一组属性
例如有关系模式C(Cno, Cname, Pcno),Cno, Cname, Pcno依次表示课程号、课程名、先修课。可知关系C只有一个码Cno,且没有任何属性对Cno部分函数依赖或传递函数依赖,所以关系C属于第三范式,同时Cno是C中的唯一决定因素,所以C也属于BC范式。
第四范式(4NF)
定义: 限制关系模式的属性之间不允许有非平凡且非函数依赖的多值依赖。
理解: 显然一个关系模式是4NF,则必为BCNF。也就是说,当一个表中的非主属性互相独立时(3NF),这些非主属性不应该有多值,若有多值就违反了4NF。
第五范式(5NF)
第五范式有以下要求:
- 必须满足第四范式
- 表必须可以分解为较小的表,除非那些表在逻辑上拥有与原始表相同的主键
第五范式是在第四范式的基础上做的进一步规范化。第四范式处理的是相互独立的多值情况,而第五范式则处理相互依赖的多值情况 。
参考文章
更多参考文章,请点击:数据库之六大范式详解1