设计表的依据。按照这个三范式设计的表不会出现数据冗余和空间浪费。
数据库三范式:
详细解释
1、第一范式:任何
一张表都应该有主键
,并且每一个字段原子性不可再分
。
第一范式:
第一范式最核心,最重要的范式,所有表的设计都要满足!
必须要有主键,并且每一个字段的原子性不可再分!
例:``student`表
学生编号 学生姓名 联系方式 1001 张三 zhangshan.com,10086 1002 李四 lisi.com,1008611 1001 王五 wangwu.com,1008612 上表不满足第一范式:
- 没有主键(学生编号存在重复)
- 联系方式字段不满足原子性不可再分(可以再分为 邮箱和电话号码)
修改为满足第一范式的表:
学生编号(pk) 学生姓名 邮箱 电话 1001 张三 zhangsna.com 10086 1002 李四 lisi.com 1008611 1003 王五 wangwu.com 1008612
2、第二范式:建立在第一范式的基础之上,所有非主键字段完全依赖主键,不能产生部分依赖
。
第二范式:
- 满足第一范式
- 非主键字段完全依赖主键,不能产生部份依赖
例如:
学生编号 学生姓名 教师编号 教师姓名 1001 张三 001 王老师 1002 李四 002 李老师 1003 王五 001 王老师 1001 张三 002 李老师 分析上表是否满足第一范式?
-------- 不满足,(没有主键)
怎么满足第一范式? 修改:
学生编号 + 教师编号(pk 复合主键) 学生姓名 教师姓名 1001 001 张三 王老师 1002 002 李四 李老师 1003 001 王五 王老师 1001 002 张三 李老师 学生编号、教师编号这两个字段做符合主键,经过修改后上表满足了第一范式,但是满足第二范式嘛?
-------- 不满足:
1001--> 张三
、001--> 王老师
(张三依赖于001、王老师依赖于001),显然非主键字段产生了对主键的部份依赖!产生部份依赖有什么缺点:数据冗余、空间浪费。(张三重复了,王老师重复了!)
为了满足第二范式,你必须这样设计:
学生和教师是
多对多
的关系!!!!!
student
表:
学生编号(pk) 学生姓名 1001 张三 1002 李四 1003 王五
teacher
表:
教师编号(pk) 教师姓名 001 王老师 002 李老师
s_t
表(学生教师关系表):
id(pk) 学生编号(fk) 教师编号(fk) 1 1001 001 2 1001 002 3 1002 002 4 1003 001 口诀:多对多怎么设计?
多对多,三张表,关系表两个外键!
3、第三范式:建立在第二范式的基础之上,所有非主键字段直接依赖主键,不能产生传递依赖
。
第三范式:
- 满足第二范式
- 所有非主键字段直接依赖主键,不能产生传递依赖。
例如:
学生班级表
学生编号(pk) 学生姓名 班级编号 班级名称 1001 张三 01 一班 1002 李四 02 二班 1003 王五 03 三班 1004 赵六 03 三班 上表是否满足第二范式?
--------------满足
是否满足第三范式?
-------------不满足:
1001 ---> 张三
、1001 ---> 01
,那么1001 --- > 01
产生了传递依赖,不符合三范式的要求。产生了数据的冗余(三班重复了)优化:班级和学生是一对多的关系!
怎么设计一对多?
class
班级表:
班级编号(pk) 班级名称 01 一班 02 二班 03 三班
studet
表(多
):
学生编号 学生姓名 班级编号(fk) 1001 张三 01 1002 李四 02 1003 王五 03 1004 赵六 03 一对多建表口诀:
一对多,两张表,多的加外键
一对多:一对多,两张表,多的加外键
多对多:多对多,三张表,关系表两外键
一对一:一对一,外键唯一
一对一
一对一放到一张表不就行了吗?还要拆分?
在实际开发中,可能一张表的字段太多了,太过于庞大,这个时候需要拆表:
没有拆表前:一张表
user
表:id login_name login_pwd realname gender email phone address …
--------------------------------------------------------------
1 张三 123 …
2 李四 456 …
这种庞大的表建议拆分为两张表:
user_login
登录信息表:id(pk) login_name login_pwd
--------------------------------
1 张三 123
2 李四 456
user_detail
用户信息表:id(pk) realname gender email phone address …
login_id(fk + unique)
-------------------------------------------------------------
001 张三 …
1
002 李四…
2
问题来了,一张表拆分为两张表,怎么保证为是
一对一
?
- 一种方案是:共享主键(同主键)——
用的少
- 常用方案:设置
唯一外键(fk + unique)
口诀:一对一表拆分
一对一,外键唯一
注意:数据库三范式是理论上的。实际和理论是有偏差的。
最终目的是为了满足用户的需求,有的时候会拿冗余来换取速度。
因为在执行sql
语句时,表和表之间的连接次数越多,查询效率越慢(笛卡尔积)
有的时候会存在冗余,但为了减少连接的次数,这样做也是合理的。(就比如上述一对一的表拆分,其实一张表就可以了,只不过表字段多,但相比于拆分为两张表来说,它的查询效率是更高的!)