数据库范式
数据库范式(Database Normal Form),是关系数据库设计时需要遵循的一系列规范。其主要目标是减少数据冗余、提高数据一致性和完整性,以及优化存储效率。
范式从低到高呈递次规范,越高的范式,数据库的冗余度就越小。 目前,关系数据库中主要的范式有: * 第一范式 (1NF) * 第二范式 (2NF) * 第三范式 (3NF) * 巴斯-科德范式 (BCNF) * 第四范式 (4NF) * 第五范式 (5NF)
在实际应用中,最常遵循的是第三范式(3NF)或BCNF。 过高的范式化可能会导致表过度拆分,增加查询的复杂性。
在了解范式之前,需要先理解几个基本概念: * 函数依赖:在一个关系中,如果通过属性X的值可以唯一确定属性Y的值,则称Y函数依赖于X,记作 X → Y。 * 码(键):可以唯一标识表中每一行数据的属性或属性组。 * 主属性:包含在任何一个候选码中的属性。 * 非主属性:不包含在任何候选码中的属性。
第一范式 (1NF)
定义:确保数据表中的每一列(字段)都是不可分割的原子数据项。 这是对关系模式最基本的要求,所有关系型数据库都必须满足第一范式。
核心要求:字段原子性,不可再分。
示例: 假设有一个订单信息表,其中“商品信息”列包含了商品名称和数量,这就不符合第一范式。
不符合1NF的表: | 订单号 | 客户 | 商品信息 | | :--- | :--- | :--- | | 1001 | 张三 | 电脑, 2台 | | 1002 | 李四 | 键盘, 1个; 鼠标, 1个 |
如何修正: 将“商品信息”拆分为多个独立的、不可再分的列。
符合1NF的表: | 订单号 | 客户 | 商品名称 | 数量 | | :--- | :--- | :--- | :--- | | 1001 | 张三 | 电脑 | 2 | | 1002 | 李四 | 键盘 | 1 | | 1002 | 李四 | 鼠标 | 1 |
第二范式 (2NF)
定义:在满足第一范式的基础上,表中每一个非主属性都必须完全函数依赖于候选码,而不能只依赖于候选码的一部分(消除部分函数依赖)。
核心要求:消除非主属性对码的“部分函数依赖”。 这个范式主要针对联合主键。如果一个表的主键只有一个字段,那么它只要符合1NF,就一定符合2NF。
示例: 假设有一个选课成绩表,使用(学号, 课程号)作为联合主键。
不符合2NF的表: (主键为 学号 + 课程号)
| 学号 | 学生姓名 | 课程号 | 课程名称 | 成绩 |
| :--- | :--- | :--- | :--- | :--- |
| S01 | 张三 | C01 | 数据库 | 85 |
| S01 | 张三 | C02 | 操作系统 | 90 |
| S02 | 李四 | C01 | 数据库 | 78 |
在这个表中:
* 成绩 完全依赖于 (学号, 课程号)。
* 学生姓名 只依赖于 学号,是部分依赖。
* 课程名称 只依赖于 课程号,也是部分依赖。
这会导致数据冗余(张三和数据库的名字重复出现)和更新异常。
如何修正: 将表拆分,消除部分依赖。
符合2NF的表:
学生表: | 学号 | 学生姓名 | | :--- | :--- | | S01 | 张三 | | S02 | 李四 |
课程表: | 课程号 | 课程名称 | | :--- | :--- | | C01 | 数据库 | | C02 | 操作系统 |
成绩表: | 学号 | 课程号 | 成绩 | | :--- | :--- | :--- | | S01 | C01 | 85 | | S01 | C02 | 90 | | S02 | C01 | 78 |
第三范式 (3NF)
定义:在满足第二范式的基础上,任何非主属性都不能依赖于其他非主属性(消除传递函数依赖)。
核心要求:确保每个非主属性都直接依赖于主键,而不是间接依赖。
示例: 假设有一个员工信息表,其中包含了部门信息。
不符合3NF的表: (主键为 员工号)
| 员工号 | 员工姓名 | 部门号 | 部门名称 | 部门经理 |
| :--- | :--- | :--- | :--- | :--- |
| E01 | 张三 | D01 | 研发部 | 王五 |
| E02 | 李四 | D02 | 市场部 | 赵六 |
| E03 | 小明 | D01 | 研发部 | 王五 |
在这个表中,存在以下依赖关系:
(员工号) → (部门号) → (部门名称, 部门经理)
部门名称 和 部门经理 依赖于 部门号 (一个非主属性),而 部门号 依赖于 员工号 (主键)。这就构成了传递依赖。
如何修正: 将存在传递依赖的属性拆分到新的表中。
符合3NF的表:
员工表: | 员工号 | 员工姓名 | 部门号 | | :--- | :--- | :--- | | E01 | 张三 | D01 | | E02 | 李四 | D02 | | E03 | 小明 | D01 |
部门表: | 部门号 | 部门名称 | 部门经理 | | :--- | :--- | :--- | | D01 | 研发部 | 王五 | | D02 | 市场部 | 赵六 |
巴斯-科德范式 (BCNF)
定义:在满足第三范式的基础上,对于表中任何一个非平凡的函数依赖 X → Y,X都必须是一个超键(Super Key)。 BCNF通常被认为是修正的第三范式,比3NF的要求更严格。
核心要求:任何属性(包括主属性和非主属性)都不能被非主属性所决定。 换言之,它消除了主属性对于码的部分和传递依赖。
与3NF的区别:3NF允许主属性被非主属性决定,而BCNF不允许。
示例: 假设有一个仓库管理表,其中一个仓库只有一个管理员,一个管理员只负责一个仓库;但一个仓库可以存放多种物品,一种物品也可以被存放在多个仓库,且有对应的数量。
符合3NF但不符合BCNF的表: (候选键为 (仓库名, 物品名))
| 仓库名 | 管理员 | 物品名 | 数量 |
| :--- | :--- | :--- | :--- |
| 仓库A | 张三 | 物品甲 | 100 |
| 仓库A | 张三 | 物品乙 | 200 |
| 仓库B | 李四 | 物品甲 | 150 |
在这个表中:
* (仓库名, 物品名) 是候选键,可以决定所有属性。
* 存在依赖 管理员 → 仓库名。
* 管理员 不是超键,但它决定了 仓库名(主属性的一部分),这违反了BCNF。
如何修正: 进行表拆分。
符合BCNF的表:
仓库管理员表: | 管理员 | 仓库名 | | :--- | :--- | | 张三 | 仓库A | | 李四 | 仓库B |
库存表: | 仓库名 | 物品名 | 数量 | | :--- | :--- | :--- | | 仓库A | 物品甲 | 100 | | 仓库A | 物品乙 | 200 | | 仓库B | 物品甲 | 150 |
更高阶的范式
- 第四范式 (4NF):在BCNF的基础上,消除多值依赖。
- 第五范式 (5NF):在4NF的基础上,消除连接依赖,确保表中的信息无法通过其他表的连接来推导。
4NF和5NF在实际的数据库设计中较少使用,因为它们处理的是更复杂的数据依赖关系。
范式化的优缺点与反范式化
优点: * 减少数据冗余:最小化数据的重复存储,节省存储空间。 * 提高数据一致性:数据只存储在一处,更新时不易产生数据不一致的情况。 * 优化写入操作:由于减少了冗余数据,插入、更新和删除操作更快。
缺点: * 查询性能可能下降:过度范式化会导致表的数量增多,查询时需要进行多次连接(JOIN),从而影响查询效率。 * 设计复杂性增加:数据库结构变得更加复杂,增加了理解和维护的难度。
反范式化: 为了提高查询性能,有时会故意违反范式规则,在表中保留一些冗余数据,以减少查询时的连接操作。这是一种用空间换时间的策略,需要在数据一致性和查询效率之间做出权衡。