今天我们来学习一下数据库的三大范式,范式可以简单理解成标准,可以帮助我们更好的设计数据库。
- 第一范式:字段不可再分
- 举例
- 我们要存储体检者的双眼视力
- 那么应该存为左眼视力和右眼视力两个字段
- 即user表里应该有left_eye和right_eye,而不能把它们存在一个字段
- 第一范式的缺点
- 下图满足了第一范式,但是存在如下问题:
- 数据冗余
- 创建系时插入异常
- 删除学生会导致系消失
- 学生转系时改动多处
- 第二范式2NF
- 定义
- 在1NF的基础上,要有键
- 所有字段分别完全依赖于键
- 如果键是多个字段组合,则不允许部分依赖于该键
- 依赖关系
- 给出键,就能唯一确定字段的值
- 如给出学号,就能唯一确定姓名,反之则不行,这种情况就称姓名依赖于学号
- 上图中不满足第二范式的地方
- 上表的键为(学号,课名)
- 但存在部分依赖:姓名依赖于学号
- 将上图根据第二范式进行改变
- 选课表(学号、课名、分数),键是学号和课名
- 学生表(学号、姓名、系名、系主任),键是学号
- 第三范式3NF
- 定义: 一个表里不能有依赖传递。
- 上图选课表中,给出学号,就能确定系名:系名依赖于学号
- 给出系名,就能确定系主任:系主任依赖于系名,所以,系主任间接依赖于学号,也就是依赖传递
- 解决办法
- 把系名和系主任单独建表
- 最后得到如下图
- 除此之外还有一个BC范式: 键中的属性也不存在间接依赖
- 数据库设计经验
- 高内聚
- 把相关的字段放到一起,不相关的分开建表
- 如果两个字段能够单独建表,那就单独建表
- 低耦合
- 如果两个表之间有弱关系
- 一对一可放在一个表,也可两个表加外键
- 一对多一般用外键
- 多对多一般建中间表
- 一对一关系举例
- 假设一个学生只能加入一个班级
- 可以把班级放在学生表里
- 学生id:1001姓名:小明班级id:4002
- 班级id:4002名称:入门1班
- 也可以单独建立关联表
- 学生id:1001姓名:小明
- 学生班级:id:2003学生id:1001班级id:4002
- 班级id:4002名称:入门1班
- 一对多关系举例
- 假设一个作者能写多本书
- 可以把书放在作者表里吗?
- 某些DBMS支持数组,可以存两个id到一个字段
- 作者id:1001,姓名:大牛,books:
[2001,3002] - 如果不支持数组,就不能这样做了
- 单独建立关系表(推荐)
- 作者id:1001姓名:大牛
- 出版:id:2001作者id:1001书id:4002,出版社id
- 出版:id:2001作者id:1001书id:4003,出版社id
- 书id:4002名称:JS入门
- 多对多关系举例
- 假设一个学生可以加入多个班级,当然每个班级也能有多个学生
- 可以把班级放在学生表里吗?
- 某些DBMS支持数组就可以放
- 如果不支持数组,就不能放了
- 单独建立关系表(推荐)
- 学生id:1001姓名:小明
- 学生班级:id:2001学生id:1001班级id:4002,有效期
- 学生班级:id:2002学生id:1001班级id:4003,有效期
- 班级id:4002名称:入门1班
- 什么时候建关联表
- 当关联自身存在属性时
- 比如关联的有效期,有效期为一年
- 比如关联的级别,店铺会员分为vip1~6