Skip to content

数据库范式

数据库范式(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),从而影响查询效率。 * 设计复杂性增加:数据库结构变得更加复杂,增加了理解和维护的难度。

反范式化: 为了提高查询性能,有时会故意违反范式规则,在表中保留一些冗余数据,以减少查询时的连接操作。这是一种用空间换时间的策略,需要在数据一致性和查询效率之间做出权衡。