(0)什么是数据库设计范式:
- 数据库设计范式:数据库表的设计依据。按照范式设计数据库表,可以避免表中数据的冗余,空间的浪费。
标准的讲法是这样子的:
- 第一范式:当关系模式R的所有属性都不能再分解为更基本的数据单位时,称R是满足第一范式,即属性不可分。
- 第二范式:如果关系模式R满足第一范式,并且R的所有非主属性都完全依赖于R的每一个候选关键属性,称R满足第二范式。
- 第三范式:设R是一个满足第一范式条件的关系模式,X是R的任意属性集,如果X非传递依赖于R的任意一个候选关键字,称R满足第三范式,即非主属性不传递依赖于键码。
通俗的讲法是这样子的:
- 第一范式:要求任何一张表必须有主键,每一个字段原子性不可再分。(属性不可分)
- 第二范式:建立在第一范式的基础之上,要求所有非主键字段完全依赖主键,不要产生部分依赖。
- 第三范式:建立在第二范式的基础之上,要求所有非主键字段直接依赖主键,不要产生传递依赖。
(1)第一范式
最核心,最重要的范式,所有表的设计都需要满足。
假设有一张表如下:
学生编号 学生姓名 联系方式 ------------------------------------------ 1001 张三 zs@gmail.com,1359999999 1002 李四 ls@gmail.com,13699999999 1001 王五 ww@163.net,13488888888
可以看出上表不满足第一范式
原因:第一,没有主键(编号重复,不能唯一标识);第二,联系方式可以分为邮箱地址和电话(可再分):
我们将其重建
学生编号(pk) 学生姓名 邮箱地址 联系电话 --------------------------------------------------------- 1001 张三 zs@gmail.com 1359999999 1002 李四 ls@gmail.com 13699999999 1003 王五 ww@163.net 13488888888
该表满足第一范式
(2)第二范式
假设有一张表
学生编号 学生姓名 教师编号 教师姓名 ---------------------------------------------------- 1001 张三 001 王老师 1002 李四 002 赵老师 1003 王五 001 王老师 1001 张三 002 赵老师
可以看出上表满足第一范式;不满足第二范式。
原因:多对多关系!(1个学生可能有多个老师,1个老师有多个学生)
学生编号 教师编号,两个字段联合做主键,复合主键(PK: 学生编号+教师编号)
学生编号+教师编号(pk) 学生姓名 教师姓名 ---------------------------------------------------- 1001 001 张三 王老师 1002 002 李四 赵老师 1003 001 王五 王老师 1001 002 张三 赵老师
上表不满足第二范式:张三”依赖1001,“王老师”依赖001,显然产生了部分依赖。
修改:使用三张表来表示多对多的关系
学生表 学生编号(pk) 学生名字 ------------------------------------ 1001 张三 1002 李四 1003 王五 教师表 教师编号(pk) 教师姓名 -------------------------------------- 001 王老师 002 赵老师 学生教师关系表 id(pk) 学生编号(fk) 教师编号(fk) ------------------------------------------------------ 1 1001 001 2 1002 002 3 1003 001 4 1001 002
总结:多对多设计,三张表,关系表两个外键!
(3)第三范式
学生编号(PK) 学生姓名 班级编号 班级名称 --------------------------------------------------------- 1001 张三 01 一年一班 1002 李四 02 一年二班 1003 王五 03 一年三班 1004 赵六 03 一年三班
1对多关系!(一个教室中有多个学生)
满足第一范式,有主键(学生编号)。
满足第二范式,因为主键不是复合主键,没有产生部分依赖。主键是单一主键。
不满足第三范式:一年一班依赖01,01依赖1001,产生了传递依赖。
修改:
班级表:一 班级编号(pk) 班级名称 ---------------------------------------- 01 一年一班 02 一年二班 03 一年三班 学生表:多 学生编号(PK) 学生姓名 班级编号(fk) ------------------------------------------- 1001 张三 01 1002 李四 02 1003 王五 03 1004 赵六 03
总结: 一对多,两张表,多的表加外键!
一对一: 实际开发中,可能存在一张表字段太多,太庞大。这个时候要拆分表。
没有拆分表之前:一张表
t_user id login_name login_pwd real_name email address........ ------------------------------------------------------------------------------------------------------ 1 zhangsan 123 张三 zhangsan@xxx 2 lisi 123 李四 lisi@xxx ...
这种庞大的表建议拆分为两张:
t_login 登录信息表 id(pk) login_name login_pwd ------------------------------------------ 1 zhangsan 123 2 lisi 123 t_user 用户详细信息表 id(pk) real_name email address........ login_id(fk+unique) ----------------------------------------------------------------------------------------- 100 张三 zhangsan@xxx 1 200 李四 lisi@xxx 2
总结:一对一,外键唯一!
注意:数据库设计三范式是理论上的;拆成多张表,查询的时候就需要连接多张表,由于笛卡尔积,查询速度慢。
实际中以空间(数据冗余)换取时间(高速)是可行的。而且不拆开表的话,SQL语句编写也简单。