关系数据库规范化理论,四大范式,完整性约束
关系数据库规范化是一种组织数据库表结构和字段的技术,目的是减少数据冗余、消除更新异常,并确保数据依赖的合理性。
一、范式基本概念
范式(Normal Form) 是符合某一种级别的关系模式的集合,分为 1NF、2NF、3NF、BCNF、4NF、5NF 等,级别越高约束越严格。
二、各范式详细说明
1. 第一范式(1NF)
要求:
- 表中每个字段都是原子性的,不可再分
- 每个字段具有相同的数据类型
- 每行数据具有唯一性标识(主键)
示例 :
不满足 1NF 的表结构:
学生 ID | 姓名 | 课程 |
---|---|---|
1 | 张三 | 数学,英语,计算机 |
满足 1NF 的表结构:
学生 ID | 姓名 | 课程 |
---|---|---|
1 | 张三 | 数学 |
1 | 张三 | 英语 |
1 | 张三 | 计算机 |
2. 第二范式(2NF)
要求:
- 满足 1NF
- 非主属性完全依赖于主键(消除部分依赖)
具体内涵:
- 完全依赖:非主属性必须依赖于整个主键,而非主键的一部分
- 部分依赖:非主属性只依赖于主键的一部分字段
示例 :
不满足 2NF 的表结构(存在部分依赖):
订单 ID | 产品 ID | 产品名称 | 数量 | 单价 |
---|---|---|---|---|
1001 | P001 | 手机 | 2 | 5000 |
1001 | P002 | 耳机 | 1 | 200 |
依赖分析:
- 主键:(订单 ID, 产品 ID)
- 部分依赖:产品名称 → 产品 ID,单价 → 产品 ID
分解为满足 2NF 的表:
订单表:
订单 ID | 产品 ID | 数量 |
---|---|---|
1001 | P001 | 2 |
1001 | P002 | 1 |
产品表:
产品 ID | 产品名称 | 单价 |
---|---|---|
P001 | 手机 | 5000 |
P002 | 耳机 | 200 |
订单ID 订单日期 产品ID 产品名称 单价 数量
3. 第三范式(3NF)
要求:
- 满足 2NF
- 非主属性之间不存在传递依赖
具体内涵:
- 传递依赖:若 A → B 且 B → C,则 C 传递依赖于 A
- 3NF 要求消除这种传递关系,确保非主属性直接依赖于主键
示例 :
不满足 3NF 的表结构(存在传递依赖):
学生 ID | 系别 | 系主任 |
---|---|---|
001 | 计算机 | 王教授 |
002 | 计算机 | 王教授 |
003 | 数学 | 李教授 |
依赖分析:
- 学生 ID → 系别 → 系主任(传递依赖)
分解为满足 3NF 的表:
学生表:
学生 ID | 系别 |
---|---|
001 | 计算机 |
002 | 计算机 |
003 | 数学 |
系别表:
系别 | 系主任 |
---|---|
计算机 | 王教授 |
数学 | 李教授 |
学生ID 系别 系主任
4. 巴斯 - 科德范式(BCNF)
要求:
- 满足 3NF
- 每个非平凡函数依赖的左边必须包含候选键
具体内涵:
- 非平凡函数依赖:X → Y 且 Y 不包含于 X
- 候选键:能唯一确定整个元组的最小属性集
- BCNF 要求每个决定因素(函数依赖的左边)都是候选键
示例解释 :
假设有表CourseInstructor
,包含:
- 课程 ID(CourseID)
- 教师 ID(InstructorID)
- 课程类型(CourseType)
函数依赖:
- (CourseID, InstructorID) → CourseType
- CourseType → InstructorID(特定类型的课程只能由特定教师教授)
候选键:
- (CourseID, InstructorID)(因为能确定所有属性)
问题 :
函数依赖CourseType → InstructorID
的左边不是候选键,违反 BCNF
分解为 BCNF:
- 课程类型表:(CourseType, InstructorID)
- 授课表:(CourseID, CourseType)
示例 :
不满足 BCNF 的表结构:
讲师 | 课程 | 教室 |
---|---|---|
张老师 | 数学 | A101 |
张老师 | 物理 | A102 |
李老师 | 数学 | A103 |
依赖分析:
- 候选键:(讲师,课程) 和 (课程,教室)
- 函数依赖:讲师 → 课程(不满足 BCNF)
分解为满足 BCNF 的表:
讲师课程表:
讲师 | 课程 |
---|---|
张老师 | 数学 |
张老师 | 物理 |
李老师 | 数学 |
课程教室表:
课程 | 教室 |
---|---|
数学 | A101 |
物理 | A102 |
数学 | A103 |
三、规范化流程图
非规范化表 第一范式: 原子性 第二范式: 消除部分依赖 第三范式: 消除传递依赖 BCNF: 消除主属性依赖 更高范式: 4NF/5NF
四、规范化步骤与示例
步骤:
- 确定表的主键
- 检查是否满足 1NF
- 消除部分依赖(达到 2NF)
- 消除传递依赖(达到 3NF)
- 消除主属性依赖(达到 BCNF)
示例 :
原始表结构:
学生 ID | 姓名 | 课程 | 成绩 | 系别 | 系主任 |
---|---|---|---|---|---|
001 | 张三 | 数学 | 90 | 计算机 | 王教授 |
001 | 张三 | 英语 | 85 | 计算机 | 王教授 |
002 | 李四 | 数学 | 92 | 数学 | 李教授 |
规范化过程:
- 确定主键:(学生 ID, 课程)
- 1NF 检查:满足(字段不可再分)
- 2NF 分解 :消除部分依赖
- 学生表:(学生 ID, 姓名,系别,系主任)
- 选课表:(学生 ID, 课程,成绩)
- 3NF 分解 :消除传递依赖
- 学生表:(学生 ID, 姓名,系别)
- 系别表:(系别,系主任)
- 选课表:(学生 ID, 课程,成绩)
五、反规范化概念
反规范化 :在特定场景下,为提高查询性能而有意引入数据冗余的做法。
适用场景:
- 频繁进行连接操作的查询
- 数据仓库和 OLAP 系统
- 对响应时间要求极高的场景
技术手段:
- 增加冗余字段
- 合并表
- 创建物化视图
六、规范化的优缺点
优点:
- 减少数据冗余
- 避免更新异常(插入 / 删除 / 修改异常)
- 提高数据完整性
- 便于数据库维护
缺点:
- 可能导致查询效率降低(需连接多个表)
- 设计和实现复杂度增加
- 对写入操作性能影响较小
七、范式选择原则
- 大多数业务系统推荐达到 3NF
- 对性能要求极高的系统可考虑 BCNF
- 数据仓库和分析系统可适当反规范化
- 避免过度规范化(超过 BCNF 的情况很少需要)
合理的数据库设计应在规范化和性能之间找到平衡点,根据业务需求灵活应用范式理论。
数据库完整性约束
一、完整性约束基本概念
数据库完整性约束 实体完整性 参照完整性 域完整性 用户定义完整性 主键约束 唯一约束 外键约束 数据类型 非空约束 检查约束 存储过程 触发器 断言
数据库完整性约束是数据库管理系统为保证数据的准确性、一致性和可靠性而实施的规则。这些约束确保数据库中的数据符合业务规则和逻辑要求,防止非法数据的插入、更新或删除。
完整性约束的分类:
- 实体完整性:确保表中每行数据的唯一性
- 参照完整性:确保表之间关联关系的有效性
- 域完整性:确保字段值符合特定的数据类型和取值范围
- 用户定义完整性:实现业务特定的约束规则
二、完整性约束的实现方式
1. 实体完整性(Entity Integrity)
实现方式:
- 主键约束(PRIMARY KEY):唯一标识表中的每一行数据
- 唯一约束(UNIQUE):确保字段值的唯一性(允许 NULL)
- 自动递增(AUTO_INCREMENT):为字段提供自动生成的唯一值
示例:
sql
sql
-- 创建表时定义主键
CREATE TABLE users (
user_id INT PRIMARY KEY,
username VARCHAR(50) UNIQUE,
email VARCHAR(100) UNIQUE
);
-- 自增主键示例
CREATE TABLE products (
product_id INT AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(100)
);
2. 参照完整性(Referential Integrity)
实现方式:
- 外键约束(FOREIGN KEY):确保一个表中的字段值引用另一个表中的有效记录
- 级联操作(CASCADE):当主表记录被删除或更新时,自动处理相关从表记录
- 空值处理(SET NULL):主表记录删除时,从表相关字段置为 NULL
示例:
作用:维护表间关系的一致性
外键约束(FOREIGN KEY)
sql
-- 部门表
CREATE TABLE departments (
dept_id INT PRIMARY KEY,
dept_name VARCHAR(50) NOT NULL
);
-- 员工表
CREATE TABLE employees (
emp_id INT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
dept_id INT,
FOREIGN KEY (dept_id) REFERENCES departments(dept_id)
ON DELETE SET NULL -- 部门删除时设为NULL
ON UPDATE CASCADE -- 部门ID更新时级联更新
);
主键 dept_id 外键 dept_id departments employees
3. 域完整性(Domain Integrity)
实现方式:
- 数据类型约束:定义字段允许的数据类型(INT, VARCHAR, DATE 等)
- 非空约束(NOT NULL):确保字段值不为 NULL
- 默认值约束(DEFAULT):为字段提供默认值
- 检查约束(CHECK):限制字段值的取值范围
示例:
sql
CREATE TABLE orders (
order_id INT PRIMARY KEY,
order_date DATE NOT NULL DEFAULT CURRENT_DATE,
amount DECIMAL(10, 2) CHECK (amount > 0),
status VARCHAR(20) CHECK (status IN ('pending', 'paid', 'shipped', 'completed'))
);
4. 用户定义完整性(User-Defined Integrity)
实现方式:
- 存储过程和触发器:在数据操作时执行自定义业务逻辑
- 断言(Assertion):定义全局约束条件(某些数据库支持)
示例:
sql
-- 创建触发器确保员工年龄在18-65岁之间
DELIMITER $$
CREATE TRIGGER check_age
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
IF NEW.age < 18 OR NEW.age > 65 THEN
SIGNAL SQLSTATE '45000' SET MESSAGE_TEXT = '员工年龄必须在18-65岁之间';
END IF;
END$$
DELIMITER ;
三、完整性约束的作用
完整性约束 防止数据不一致 维护数据质量 保证业务规则 简化应用开发 实体完整性 参照完整性 域完整性 用户定义完整性 减少应用层验证逻辑
四、完整性约束与性能
性能影响:
- 约束检查会增加数据库操作的开销
- 复杂约束(如触发器)可能导致性能下降
优化建议:
- 在高并发场景下,权衡约束的必要性
- 使用数据库内置约束替代触发器
- 批量操作前临时禁用约束,操作后重新启用
五、完整性约束的管理
常用操作:
sql
-- 添加约束
ALTER TABLE employees ADD CONSTRAINT fk_dept FOREIGN KEY (dept_id) REFERENCES departments(dept_id);
-- 删除约束
ALTER TABLE employees DROP FOREIGN KEY fk_dept;
-- 禁用约束(临时)
SET FOREIGN_KEY_CHECKS = 0; -- MySQL
-- 启用约束
SET FOREIGN_KEY_CHECKS = 1; -- MySQL