--- title: "05-三范式" created: 2025-11-25 tags: - 项目筑基 --- # 三范式 什么是数据库设计范式 数据库表的设计依据 如何进行数据库表的设计 第一范式 要求任何一张表必须要有主键 每一个字段原子性不可再分 第二范式 建立在第一范式基础之上 要求所有非主键字段完全依赖主键 不要产生部分依赖 第三范式 建立在第二范式基础之上 要求所有非主键字段直接依赖主键 不要产生传递依赖 按照以上的范式进行 可以避免表中数据的冗余、空间的浪费 ## 第一范式 最核心、最重要的范式 所有表的设计都需要满足 必须要有主键 并且每一个字段都是原子性不可再分 ![[image-d062124f.png]] 第一:没有主键 第二:联系方式可以分为邮箱地址和电话(可再分) 可以这样改 ![[image-a3dd73d6.png]] 那姓名里的姓和名也可以再分呀 所谓不可再分不是说一定要强行去拆分 要符合逻辑 强行把姓名拆开来当然可以 但那样逻辑反而混乱了 没有意义 关于第一范式,每一行必须唯一,也就是每个表必须有主键,这是我们数据库设计的最基本要求,主要通常采用数值型或定长字符串表示,关于列不可再分,应该根据具体的情况来决定。如联系方式,为了开发上的便利行可能就采用 一个字段了。 (实际上主键一般不用有实际意义的字段 因为ssssvip可能会有改卡号的需求……) ## 第二范式 建立在第一范式的基础之上 要求所有非主键字段 必须完全依赖主键 不要产生部分依赖 比如一张老师学生关系表 ![[image-4c815caa.png]] 首先就不满足第一范式——没有主键 可以设置联合主键PK(学生编号,教师编号) ![[image-d76d6f27.png]] 现在它满足第一范式 那么它满足第二范式吗 部分依赖—— 张三依赖的是1001,王老师依赖的是001 他们都只依赖于主键的一部分 所以不满足第二范式 缺点是什么?数据冗余、空间浪费 ——张三重复了、王老师也重复了…… 那该怎么改 考虑一下学生老师的关系—— 一个学生对应多个老师 一个老师对应多个学生 多对多关系 其实在前面E-R图里也有接触过这种概念 对于多对多的联系 一般会采取一个中间量 ![[image-89f8465e.png]] 用这个思路——使用三张表来表示多对多的关系 ![[image-2b24aaca.png]] ![[image-577d4098.png]] ![[image-c773fdb3.png]] 如果一个表是单一主键,那么它就复合第二范式,部分依赖和主键有关系 这是典型的“多对多”的设计 多对多,三张表——关系表俩外键 ## 第三范式 建立在第二范式的基础上 要求所有非主键字段必须直接依赖主键 不用产生传递依赖 ![[image-72eb9506.png]] 满足第一范式 有主键 满足第二范式 (班级和学生的关系——一对多 一个班级多个学生) 它是单一主键 不是复合主键 没产生部分依赖 所有的都依赖于学生编号 满足第三范式吗? 传递依赖—— 一年一班依赖01,01依赖1001 产生了传递依赖 不符合第三范式要求 产生了数据的冗余 又该怎么改? 从上表可以看出,班级名称字段存在冗余,因为班级名称字段没有直接依赖于主键,班级名称字段依赖于班级编号,班级编号依赖于学生编号,那么这就是传递依赖,解决的办法是将冗余字段单独拿出来建立表 ![[image-6397e6d1.png]] ![[image-594d5695.png]] 这是典型的一对多,一存储在一张表中,多存储在一张表中,在多的那张表中添加外键指向一的一方的主键 一对多 两张表 多的表加外键 ## 总结 第一范式:有主键,具有原子性,字段不可分割 第二范式:完全依赖,没有部分依赖 第三范式:没有传递依赖 数据库设计尽量遵循三范式,但是还是根据实际情况进行取舍,有时可能会拿冗余换速度,最终用目的要满足客户需求(理论与实践) 避免冗余就拆开表 拆开表但是需要表连接 表连接一多因为笛卡尔积现象速度就越慢 所以这还是时间和空间的一个取舍问题 实际上可能会存在一张表字段太多 太庞大 对于一对一的关系也可能需要拆分 两种方案: 第一种设计方案:主键共享 (用得较少) 第二种设计方案:外键唯一 对于 t\_user | | | | | | | | | --- | --- | --- | --- | --- | --- | --- | | id | login\_name | login\_pwd | real\_name | email | address | sex | | 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 | sex | login\_id(fk+unique) | | 100 | 张三 | zhangsan@xxx | 上海 | 男 | 1 | | 200 | 李四 | lisi@xxx | 北京 | 女 | 2 | | …… | | | | | | 在一个表上多加一列外键 并加上唯一性约束 实现的功能就使得两个表的字段联系上 so 一对一 拆分表 外键唯一 一对多 两张表 多的表加外键 多对多 三张表 关系表俩外键 tips: ![[image-d653f2c5.png]] --- ⬅️ [[04-设计数据库|04-设计数据库]] 🏠 [[00-数据库|00-数据库]] ➡️ [[06-表的管理|06-表的管理]]