数据库的设计

数据库设计:范式与实操流程

自用复习版

目录

一、数据库设计的核心------范式

范式是关系型数据库设计的通用规则 ,核心目的是减少数据冗余避免增删改查的异常问题 。目前有6种范式,实际开发中做到第三范式(3NF) 就完全满足大部分业务需求,也是我们学习的核心。

所有高等级范式的前提:必须先满足低等级范式(比如2NF基于1NF,3NF基于2NF)。

1.1 第一范式(1NF):列的原子性

核心要求 :表中的每一列都必须是不可再分的基本数据类型 ,列的值不能拆成多个子值,这是数据库设计的基础要求

简单说:一列只能存一个含义的信息

举例子

不满足1NF的表(学生表)

学号 姓名 联系方式
001 张三 138xxxx1234、zhangsan@qq.com
原因:联系方式列可以拆分成手机号邮箱,列值可再分,违反原子性。

满足1NF的表(学生表)

学号 姓名 手机号 邮箱
001 张三 138xxxx1234 zhangsan@qq.com
原因:每一列都是不可再分的基本类型,一个列只存一个信息。

1.2 第二范式(2NF):消除部分函数依赖

前提 :表已经满足第一范式(1NF)
核心要求 :如果表使用复合主键 (多个字段组成的主键,也叫候选键),那么非主键列必须完全依赖整个复合主键 ,不能只依赖复合主键中的某一个字段(这种情况叫部分函数依赖)。

简单说:复合主键的表,非主键列要"缺一不可"的依赖主键整体,不能只认主键的其中一个字段。

举例子(经典学生成绩表)

不满足2NF的表 (学生成绩表),复合主键:学号+课程号

学号 课程号 姓名 课程名 成绩
001 数学01 张三 小学数学 90
001 语文01 张三 小学语文 85
002 数学01 李四 小学数学 95

问题分析

  • 姓名:只依赖学号(知道学号001就知道是张三,和课程号无关)→ 部分依赖
  • 课程名:只依赖课程号(知道课程号数学01就知道是小学数学,和学号无关)→ 部分依赖
  • 成绩:依赖学号+课程号(必须同时知道两个字段才知道分数)→ 完全依赖

不满足2NF的4个问题

  1. 数据冗余:姓名、课程名重复存储(比如张三出现2次,小学数学出现2次);
  2. 更新异常:修改课程名"小学数学"为"小学数科",需要改所有课程号为数学01的记录,漏改就会数据不一致;
  3. 插入异常:想新增一门课程"英语01-小学英语",但暂时没有学生选,主键学号为空,无法插入;
  4. 删除异常:删除学号001的所有成绩,会连带着把"张三"这个学生信息一起删掉。

满足2NF的解决方法:拆分表

将原表按实体独立的原则拆成3个表,消除部分依赖:

  1. 学生表(主键:学号):| 学号 | 姓名 |
  2. 课程表(主键:课程号):| 课程号 | 课程名 |
  3. 成绩表(复合主键:学号+课程号):| 学号 | 课程号 | 成绩 |

如果一个表用多个字段凑成的复合主键 (比如 "学号 + 课程号"),那表里除了主键之外的其他列(比如成绩、姓名这些),必须得靠整个复合主键一起才能确定 ------ 不能只靠主键里的某一个字段(比如只靠学号就能确定姓名,只靠课程号就能确定课程名)

拆分后每个表的非主键列都完全依赖自身主键,彻底解决增删改异常和数据冗余问题。

1.3 第三范式(3NF):消除传递函数依赖

前提 :表已经满足第二范式(2NF)
核心要求非主键列之间不能存在传递依赖 ,非主键列必须直接依赖主键,而不能通过其他非主键列间接依赖主键。

简单说:表中只能有主键→非主键列 的直接关系,不能有主键→非主键列A→非主键列B的间接关系。

举例子

不满足3NF的表(学生表),主键:学号

学号 姓名 班级号 班级班主任
001 张三 一班 王老师
002 李四 一班 王老师
003 王五 二班 李老师

问题分析

  • 姓名、班级号:直接依赖学号 → 符合要求
  • 班级班主任:依赖班级号 ,而非直接依赖学号,形成传递依赖:学号→班级号→班级班主任 → 违反3NF

不满足3NF的问题

和2NF类似,会出现数据冗余(王老师重复存储)、更新异常(改一班班主任为张老师,需修改所有一班学生记录)、插入异常(新建三班无学生,无法插入班级号和班主任)、删除异常(删除二班最后一个学生,连班主任李老师信息一起删掉)。

满足3NF的解决方法:拆分表

将传递依赖的字段拆成独立的实体表,消除间接依赖:

  1. 学生表(主键:学号):| 学号 | 姓名 | 班级号 |
  2. 班级表(主键:班级号):| 班级号 | 班级班主任 |

拆分后,学生表的非主键列直接依赖主键,班级表的属性也贴合自身实体,完全满足3NF。

范式小总结

  1. 1NF:列不可再分(原子性)→ 基础;
  2. 2NF:基于1NF,消除部分函数依赖(复合主键专用)→ 实体独立;
  3. 3NF:基于2NF,消除传递函数依赖 → 无间接依赖;
  4. 实用技巧:拆分表后,可选择性加少量冗余列 (反范式设计),比如订单表中加商品名称,避免频繁联表查询,兼顾规范性查询效率

二、数据库设计完整实操流程

范式是设计规则,而实际开发中需要按业务梳理→关系设计→建表的流程来做,三步就能完成基础数据库设计,适合新手入门:

步骤1:梳理业务,提取概念类(实体+属性)

从实际业务中找出核心实体 (业务中的关键对象,对应数据库的表),再提取每个实体的属性(实体的特征,对应数据库的列)。

  • 实体:比如学生管理系统的「学生」「课程」「班级」;电商系统的「用户」「商品」「订单」;
  • 属性:比如「学生」的属性是学号、姓名、班级号;「课程」的属性是课程号、课程名、学分。

步骤2:确定实体间的关系,绘制E-R图

梳理清楚实体之间的关联关系(一对一/一对多/多对多),然后画出E-R图(实体关系图),把「实体、属性、关系」可视化,这是设计的核心环节,能避免后续建表混乱。

步骤3:依据E-R图,结合范式创建数据库表

按照E-R图的内容,将实体拆成独立的表,同时遵循3NF设计规则,处理好实体间的关联字段(外键),最终生成数据库表结构。

三、E-R图基础与实体关系处理

E-R图是数据库设计的可视化工具,核心是把业务转化为直观的图形,方便后续建表,也是面试常考的基础点。

3.1 E-R图三要素

  1. 实体 :用矩形表示,写实体名称(比如学生、课程);
  2. 属性 :用椭圆形表示,写属性名称,用线和对应实体连接(比如学号是学生的属性);
  3. 关系 :用菱形表示,写关系名称,用线和关联的实体连接,线上标注关系类型(一对一/一对多/多对多)。

3.2 一对一关系处理

定义 :A实体的一个记录,只能对应B实体的一个记录,反之亦然。
例子 :学生 ↔ 学生档案(一个学生只有一个档案,一个档案只属于一个学生)。
实操方法

  1. 分别为两个实体创建独立的表;
  2. 其中一个表 中添加另一个表的主键作为外键(比如在「学生档案表」中加「学号」,关联学生表)。

3.3 一对多关系处理

定义 :A实体的一个记录,可以对应B实体的多个记录,而B实体的一个记录只能对应A实体的一个记录(最常见的关系)。
例子 :班级 → 学生(一个班级有多个学生,一个学生只属于一个班级);商品 → 订单详情(一个商品出现在多个订单详情,一个订单详情只对应一个商品)。
实操方法

  1. 分别为两个实体创建独立的表;
  2. 在**「多」的一方的表中,添加「一」的一方**的主键作为外键(比如在「学生表」中加「班级号」,关联班级表)。

3.4 多对多关系处理

定义 :A实体的一个记录,可以对应B实体的多个记录,B实体的一个记录也可以对应A实体的多个记录。
例子 :学生 ↔ 课程(一个学生选多门课,一门课被多个学生选);用户 ↔ 商品(一个用户收藏多个商品,一个商品被多个用户收藏)。
实操方法

  1. 分别为两个实体创建独立的实体表
  2. 新建一个中间关系表 (核心),表中包含两个实体表的主键作为复合外键,还可以添加关联属性;
  3. 例子:学生和课程的中间表是「成绩表」,包含学号(外键)、课程号(外键),还加了「成绩」这个关联属性。

四、自用复习小tips

  1. 范式的核心是拆分:把有冗余、有依赖的表拆成独立的实体表,记住"1NF原子性、2NF消部分依赖、3NF消传递依赖"即可;
  2. 3NF是通用标准:不用刻意追求更高阶的范式(4NF/5NF),实际业务中3NF足够,过度设计会增加联表查询的复杂度;
  3. 实体关系的核心:一对多靠外键,多对多靠中间表,一对一灵活加外键;
  4. E-R图是桥梁:把业务语言转化为数据库语言,画好E-R图,建表就不会乱。
相关推荐
zhouping@2 小时前
JAVA的学习笔记day05
java·笔记·学习
luckyzlb2 小时前
02-kafka(01润色版)
java·中间件·kafka
Gauss松鼠会2 小时前
openGauss数据库源码解析系列文章——存储引擎源码解析(一)
数据库·oracle·性能优化·database·opengauss
ByNotD0g2 小时前
Tomcat中的回显问题
java·tomcat
云澜哥哥2 小时前
MyBatis 实战指南:特殊符号处理与高效批量操作
java·jvm·mybatis
CRMEB2 小时前
电商项目中订单流程可以使用哪些设计模式?如何开发?
java·设计模式·gitee·开源·php·crmeb
CNAHYZ2 小时前
Apache HttpClient 配置 SSL 证书指南
java·spring boot·http
格鸰爱童话2 小时前
向AI学习项目技能(三)
java·人工智能·python·学习
y = xⁿ2 小时前
【黑马店铺二刷day02】将店铺查询信息添加到Redis中的业务操作
数据库·redis·缓存