数据库三范式:减少数据冗余与确保一致性
这个问题是数据库设计的基础,理解三范式能从根源避免数据冗余和不一致!数据库三范式的核心是逐步减少数据冗余、规范数据存储,每一级范式都建立在对上一级的满足之上。
核心定义
-
第一范式(1NF):列不可再分,确保数据原子性。
-
第二范式(2NF):在1NF基础上,消除部分函数依赖,所有非主键列完全依赖于主键。
-
第三范式(3NF):在2NF基础上,消除传递函数依赖,非主键列不依赖于其他非主键列。
第一范式(1NF):列不可再分
案例:反例(不满足1NF)
假设设计“用户表”,其中“联系方式”列包含电话和邮箱,格式如下:
| 用户ID(主键) | 用户名 | 联系方式 |
|---|---|---|
| 1 | 张三 | 138xxxx1234,zhangsan@xxx.com |
| 2 | 李四 | 139xxxx5678,lisi@xxx.com |
问题
“联系方式”列可拆分为“电话”和“邮箱”两个独立字段,不符合“原子性”要求,后续查询、筛选(如按电话搜索)会非常不便。
正例(满足1NF)
拆分可分割列,确保每列只存储单一类型数据:
| 用户ID(主键) | 用户名 | 电话 | 邮箱 |
|---|---|---|---|
| 1 | 张三 | 138xxxx1234 | zhangsan@xxx.com |
| 2 | 李四 | 139xxxx5678 | lisi@xxx.com |
第二范式(2NF):消除部分函数依赖
前提
-
满足1NF。
-
主键必须是“复合主键”(由多个字段组成),才可能存在“部分依赖”(非主键列只依赖复合主键中的某一个字段)。
案例:反例(不满足2NF)
假设设计“订单详情表”,复合主键为“订单ID+商品ID”,表结构如下:
| 订单ID(主键1) | 商品ID(主键2) | 商品名称 | 商品单价 | 购买数量 | 订单金额 |
|---|---|---|---|---|---|
| 001 | A01 | 手机 | 5000 | 2 | 10000 |
| 001 | A02 | 耳机 | 300 | 1 | 300 |
| 002 | A01 | 手机 | 5000 | 1 | 5000 |
问题
-
“商品名称”“商品单价”只依赖“商品ID”(复合主键中的一个字段),不依赖“订单ID”,属于“部分函数依赖”。
-
数据冗余严重:同一商品(如A01手机)的名称和单价重复存储,修改时需同步修改所有相关记录,易出现不一致。
正例(满足2NF)
拆分表,消除部分依赖,拆分为“订单详情表”和“商品表”:
- 商品表(主键:商品ID)
| 商品ID | 商品名称 | 商品单价 |
|---|---|---|
| A01 | 手机 | 5000 |
| A02 | 耳机 | 300 |
- 订单详情表(主键:订单ID+商品ID)
| 订单ID | 商品ID | 购买数量 | 订单金额 |
|---|---|---|---|
| 001 | A01 | 2 | 10000 |
| 001 | A02 | 1 | 300 |
| 002 | A01 | 1 | 5000 |
第三范式(3NF):消除传递函数依赖
前提
-
满足2NF。
-
非主键列之间存在“传递依赖”(A依赖主键,B依赖A,即B传递依赖主键)。
案例:反例(不满足3NF)
基于2NF的“订单详情表”,扩展后包含“用户地址”,表结构如下:
| 订单ID(主键) | 用户ID | 商品ID | 购买数量 | 订单金额 | 用户地址 |
|---|---|---|---|---|---|
| 001 | U01 | A01 | 2 | 10000 | 北京市朝阳区 |
| 002 | U01 | A02 | 1 | 300 | 北京市朝阳区 |
| 003 | U02 | A01 | 1 | 5000 | 上海市浦东新区 |
问题
-
主键是“订单ID”,“用户地址”依赖“用户ID”,而“用户ID”依赖“订单ID”,属于“传递依赖”(用户地址→用户ID→订单ID)。
-
数据冗余:同一用户(如U01)的地址重复存储,用户修改地址时需同步修改所有相关订单记录,易出错。
正例(满足3NF)
拆分表,消除传递依赖,拆分为“订单表”“用户表”“商品表”(已存在):
- 用户表(主键:用户ID)
| 用户ID | 用户地址 |
|---|---|
| U01 | 北京市朝阳区 |
| U02 | 上海市浦东新区 |
- 订单表(主键:订单ID)
| 订单ID | 用户ID | 商品ID | 购买数量 | 订单金额 |
|---|---|---|---|---|
| 001 | U01 | A01 | 2 | 10000 |
| 002 | U01 | A02 | 1 | 300 |
| 003 | U02 | A01 | 1 | 5000 |
关键补充
- 三范式的核心是“减少冗余、保证数据一致性”,但并非绝对:实际设计中可能为了查询效率,适当保留少量冗余(如数据仓库中的汇总表),这是“反范式”设计,需结合场景权衡。