数据库范式
范式(Normal Form)是关系型数据库表结构设计的规则集,回答"同一张表里该放哪些列"。核心目标是消除数据冗余和更新异常(插不进、改一处要改多处、删数据误删其他信息)。范式从低到高逐级约束更严:满足高一级必然满足低一级。实际工程几乎都停在 3NF/BCNF,再往上是理论完备但过度拆分的学术概念。
范式的层次
| 范式 | 核心要求 | 解决的异常 |
|---|---|---|
| 1NF | 列不可再分(原子性) | 无(只是表的基本形态) |
| 2NF | 1NF + 非主属性完全依赖主键(消除部分依赖) | 部分依赖导致的冗余 |
| 3NF | 2NF + 非主属性不传递依赖主键 | 传递依赖导致的更新异常 |
| BCNF | 3NF + 每个决定因素都是候选键 | 主属性间的部分/传递依赖 |
| 4NF/5NF | 消除多值依赖 / 连接依赖 | 理论完备,工程少用 |
1NF:列不可再分
每列只存一个值,不存列表或复合结构(如"电话"列不能存"手机:138, 座机:010"):
-- ❌ 违反 1NF:phone 列存了两个值
CREATE TABLE user (id INT, name VARCHAR(20), phone VARCHAR(50));
INSERT INTO user VALUES (1, '张三', '13800138000,010-12345678');
-- ✅ 符合 1NF:拆成多行或单独电话表
CREATE TABLE user_phone (
user_id INT, phone VARCHAR(20),
PRIMARY KEY (user_id, phone)
);2NF:消除部分依赖
联合主键下,非主属性不能只依赖主键的一部分。2NF 只对"联合主键"的表有意义:
-- ❌ 违反 2NF:score 依赖(学号,课程)完全;teacher 只依赖课程(部分依赖)
CREATE TABLE score (
stu_id INT, course_id INT, score INT, teacher VARCHAR(20),
PRIMARY KEY (stu_id, course_id)
);
-- teacher 只跟 course 有关,却存进了以(学号,课程)为主键的表→冗余
-- ✅ 拆成两张表
CREATE TABLE score (stu_id INT, course_id INT, score INT, PRIMARY KEY (stu_id, course_id));
CREATE TABLE course (course_id INT PRIMARY KEY, teacher VARCHAR(20));3NF:消除传递依赖
非主属性不能依赖其他非主属性(间接依赖主键):
-- ❌ 违反 3NF:dept_name 依赖 dept_id,dept_id 依赖 emp_id → 传递依赖
CREATE TABLE emp (emp_id INT PRIMARY KEY, emp_name VARCHAR(20), dept_id INT, dept_name VARCHAR(20));
-- ✅ 拆开:emp 只留 dept_id,部门信息独立成表
CREATE TABLE emp (emp_id INT PRIMARY KEY, emp_name VARCHAR(20), dept_id INT);
CREATE TABLE dept (dept_id INT PRIMARY KEY, dept_name VARCHAR(20));BCNF:主属性间也不能有依赖
3NF 不约束"主属性"之间的依赖,BCNF 把规则推到所有属性。典型反例:
-- 教师-课程-班级:一个教师只教一门课,一门课可有多个班
-- (学生,课程)→教师 是主键;但 教师→课程 是"决定因素不是候选键"
CREATE TABLE teach (stu_id INT, course_id INT, teacher VARCHAR(20),
PRIMARY KEY (stu_id, course_id)); -- teacher→course 违反 BCNF(teacher 不是候选键)BCNF 违反在实际中少且影响小,多数工程到 3NF 就够。
范式 vs 反范式
范式消除冗余但增加 JOIN,反范式(Denormalization)故意冗余换取查询性能——OLTP 与 OLAP 的取舍不同:
| 维度 | 规范化(3NF) | 反规范化 |
|---|---|---|
| 目标 | 消除冗余、保证一致性 | 减少 JOIN、提升查询性能 |
| 写操作 | 一次只改一处 | 多处冗余需同步更新 |
| 读操作 | 多次 JOIN | 单表直接读 |
| 适用 | OLTP 交易系统 | 读多写少、报表分析 |
反范式常见手法:冗余列(订单表冗余商品名)、预计算列(存订单金额汇总)、表拆分(垂直拆宽表为冷热列)。判断标准:读多写少且查询频繁 JOIN 才值得反范式,写多或一致性要求高保持范式。
ER 建模基础
ER 模型(实体-关系)是设计表结构前的概念建模:实体画矩形、属性画椭圆、关系画菱形。核心是确定实体间关系基数:
| 关系 | 表示 | 建表方式 |
|---|---|---|
| 1:1 | 一个学生对应一个学籍档案 | 任选一边加外键,或共用主键 |
| 1:N | 一个部门多个员工 | 多的一边(员工表)加部门外键 |
| M:N | 一个学生多门课、一门课多个学生 | 中间表(选课表)存两个外键 |
ER 建模与 建表 的字段规范(命名、类型、必备时间字段)、MySQL 的存储引擎选择配合使用,是数据库设计的完整链路。