数据库设计规范化是关系型数据库设计过程中需要遵循的核心准则,目的是消除数据冗余、保证数据一致性、降低数据维护的复杂度,规范化的要求按照层级从低到高分为五个阶段,每个阶段都有明确的约束条件。

第一范式:字段原子性
第一范式是最基础的规范化要求,核心是所有字段的值都必须是不可再拆分的原子值,不能存在复合字段或者多值字段。比如如果某个表的address字段同时存储了省份、城市、街道信息,就不符合第一范式的要求,需要拆分为province、city、street三个独立字段。
不符合第一范式的表结构示例:
-- 不符合第一范式的用户表
CREATE TABLE user_info (
id INT PRIMARY KEY,
name VARCHAR(50),
-- 地址字段包含多个信息,可再拆分
address VARCHAR(200),
phone VARCHAR(20)
);
符合第一范式的表结构示例:
-- 符合第一范式的用户表
CREATE TABLE user_info (
id INT PRIMARY KEY,
name VARCHAR(50),
province VARCHAR(20),
city VARCHAR(20),
street VARCHAR(100),
phone VARCHAR(20)
);
第二范式:消除部分依赖
第二范式在第一范式的基础上,要求表中的所有非主键字段必须完全依赖于整个主键,而不能只依赖主键的一部分。这个要求只针对主键是联合主键的表,如果主键是单个字段,天然满足第二范式。
比如有一个学生选课表,主键是student_id和course_id的联合主键,表中还有student_name字段,这个字段只依赖于student_id,不依赖于course_id,就属于部分依赖,不符合第二范式。
不符合第二范式的表结构示例:
-- 不符合第二范式的学生选课表
CREATE TABLE student_course (
student_id INT,
course_id INT,
student_name VARCHAR(50),
course_name VARCHAR(50),
score DECIMAL(5,2),
PRIMARY KEY (student_id, course_id)
);
符合第二范式的拆分方案:
-- 学生表
CREATE TABLE student (
student_id INT PRIMARY KEY,
student_name VARCHAR(50)
);
-- 课程表
CREATE TABLE course (
course_id INT PRIMARY KEY,
course_name VARCHAR(50)
);
-- 选课关系表,只存关联关系和学生课程对应的成绩
CREATE TABLE student_course (
student_id INT,
course_id INT,
score DECIMAL(5,2),
PRIMARY KEY (student_id, course_id),
FOREIGN KEY (student_id) REFERENCES student(student_id),
FOREIGN KEY (course_id) REFERENCES course(course_id)
);
第三范式:消除传递依赖
第三范式在第二范式的基础上,要求表中的所有非主键字段必须直接依赖于主键,不能存在传递依赖,也就是非主键字段不能依赖于其他非主键字段。
比如有一个员工表,字段包括emp_id(主键)、emp_name、dept_id、dept_name,其中dept_name依赖于dept_id,dept_id依赖于emp_id,就形成了传递依赖,不符合第三范式。
不符合第三范式的表结构示例:
-- 不符合第三范式的员工表
CREATE TABLE employee (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(50),
dept_id INT,
dept_name VARCHAR(50)
);
符合第三范式的拆分方案:
-- 部门表
CREATE TABLE department (
dept_id INT PRIMARY KEY,
dept_name VARCHAR(50)
);
-- 员工表,只存部门id作为外键
CREATE TABLE employee (
emp_id INT PRIMARY KEY,
emp_name VARCHAR(50),
dept_id INT,
FOREIGN KEY (dept_id) REFERENCES department(dept_id)
);
第四范式:消除多值依赖
第四范式是在第三范式的基础上,要求表中不能存在一个主键对应多个独立的多值属性,也就是要消除非平凡的多值依赖。比如一个员工表,一个员工可能有多个技能和多个紧急联系人,这两个属性是相互独立的,放在同一个表中就会出现多值依赖问题。
不符合第四范式的表结构示例:
-- 不符合第四范式的员工信息表
CREATE TABLE emp_info (
emp_id INT,
skill VARCHAR(50),
contact VARCHAR(50),
PRIMARY KEY (emp_id, skill, contact)
);
符合第四范式的拆分方案:
-- 员工技能表
CREATE TABLE emp_skill (
emp_id INT,
skill VARCHAR(50),
PRIMARY KEY (emp_id, skill),
FOREIGN KEY (emp_id) REFERENCES employee(emp_id)
);
-- 员工紧急联系人表
CREATE TABLE emp_contact (
emp_id INT,
contact VARCHAR(50),
PRIMARY KEY (emp_id, contact),
FOREIGN KEY (emp_id) REFERENCES employee(emp_id)
);
第五范式:消除连接依赖
第五范式也叫投影连接范式,要求表中的所有连接依赖都必须是由候选键隐含的,也就是表不能分解成更小的表再通过自然连接恢复原表,除非这些更小的表都包含原表的候选键。第五范式是最高级别的规范化要求,实际业务场景中很少需要达到这个层级,只有在数据结构非常复杂、存在多重连接依赖的场景下才会使用。
第五范式的判断相对复杂,通常如果表已经满足第四范式,且没有可以拆分后通过连接恢复的多重依赖关系,就满足第五范式的要求。
规范化程度的权衡
虽然规范化层级越高,数据冗余越少,但是过高的规范化会导致表的数量变多,查询时需要关联多张表,反而会降低查询效率。实际设计数据库时,通常达到第三范式就可以满足大部分业务场景的需求,不需要强行追求更高的规范化层级,需要根据业务的实际读写场景做适当的反规范化调整。