数据库范式(Normal Forms)是一组设计规则,用于减少数据冗余并提高数据完整性。范式理论由E.F. Codd提出,旨在通过结构化表关系来优化关系数据库设计。
基本要求: - 每个表必须有主键 - 每列包含原子值(不可再分) - 每列中的值类型相同 - 列名唯一 - 列的顺序无关紧要
示例:
-- 不符合1NF的表(多值存储在单个单元格中)
CREATE TABLE orders (
order_id INT,
products VARCHAR(200) -- 存储如"手机,平板,耳机"这样的值
);
-- 符合1NF的表
CREATE TABLE orders (
order_id INT PRIMARY KEY
);
CREATE TABLE order_items (
item_id INT PRIMARY KEY,
order_id INT,
product_name VARCHAR(50),
FOREIGN KEY (order_id) REFERENCES orders(order_id)
);
要求: - 满足1NF - 所有非主键列必须完全依赖于整个主键(不能部分依赖)
示例:
-- 不符合2NF的表(price部分依赖于product_id)
CREATE TABLE order_items (
order_item_id INT PRIMARY KEY,
order_id INT,
product_id INT,
product_name VARCHAR(50),
price DECIMAL(10,2),
quantity INT
);
-- 符合2NF的设计
CREATE TABLE products (
product_id INT PRIMARY KEY,
product_name VARCHAR(50),
price DECIMAL(10,2)
);
CREATE TABLE order_items (
order_item_id INT PRIMARY KEY,
order_id INT,
product_id INT,
quantity INT,
FOREIGN KEY (product_id) REFERENCES products(product_id)
);
要求: - 满足2NF - 非主键列之间不能有传递依赖(所有非主键列必须直接依赖于主键)
示例:
-- 不符合3NF的表(customer_city依赖于customer_zip,而不是直接依赖于order_id)
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
customer_name VARCHAR(100),
customer_zip VARCHAR(10),
customer_city VARCHAR(50)
);
-- 符合3NF的设计
CREATE TABLE customers (
customer_id INT PRIMARY KEY,
customer_name VARCHAR(100),
zip_code VARCHAR(10),
city VARCHAR(50)
);
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
要求: - 满足3NF - 对于任何非平凡的函数依赖X→Y,X必须是超键
示例:
-- 不符合BCNF的表(假设一个教授可以教授多门课程,但每门课程只能由一个教授教授)
CREATE TABLE teaching (
professor_id INT,
course_id INT,
textbook VARCHAR(100),
PRIMARY KEY (professor_id, course_id)
);
-- 问题:如果textbook由course_id决定,就违反了BCNF
-- 符合BCNF的设计
CREATE TABLE courses (
course_id INT PRIMARY KEY,
textbook VARCHAR(100)
);
CREATE TABLE teaching (
professor_id INT,
course_id INT,
PRIMARY KEY (professor_id, course_id),
FOREIGN KEY (course_id) REFERENCES courses(course_id)
);
要求: - 满足BCNF - 没有多值依赖
示例:
-- 不符合4NF的表(存在多值依赖)
CREATE TABLE employee_skills_languages (
employee_id INT,
skill VARCHAR(50),
language VARCHAR(50),
PRIMARY KEY (employee_id, skill, language)
);
-- 问题:技能和语言是独立的属性,但被放在同一个表中
-- 符合4NF的设计
CREATE TABLE employee_skills (
employee_id INT,
skill VARCHAR(50),
PRIMARY KEY (employee_id, skill)
);
CREATE TABLE employee_languages (
employee_id INT,
language VARCHAR(50),
PRIMARY KEY (employee_id, language)
);
要求: - 满足4NF - 表不能被无损分解为更小的表(没有连接依赖)
示例:
-- 不符合5NF的表(存在连接依赖)
CREATE TABLE sales (
salesperson_id INT,
product_id INT,
region_id INT,
PRIMARY KEY (salesperson_id, product_id, region_id)
);
-- 假设业务规则是:销售人员在某个区域销售某些产品
-- 符合5NF的设计(如果确实存在连接依赖)
CREATE TABLE salesperson_region (
salesperson_id INT,
region_id INT,
PRIMARY KEY (salesperson_id, region_id)
);
CREATE TABLE salesperson_product (
salesperson_id INT,
product_id INT,
PRIMARY KEY (salesperson_id, product_id)
);
CREATE TABLE product_region (
product_id INT,
region_id INT,
PRIMARY KEY (product_id, region_id)
);
虽然范式有助于减少冗余和提高数据完整性,但有时出于性能考虑需要进行反规范化:
反规范化场景: 1. 频繁的复杂查询需要多表连接 2. 报表和分析需求 3. 读密集型应用
示例:
-- 反规范化设计:在订单表中存储客户名称
CREATE TABLE orders (
order_id INT PRIMARY KEY,
customer_id INT,
customer_name VARCHAR(100), -- 反规范化字段
order_date DATETIME,
total_amount DECIMAL(10,2),
FOREIGN KEY (customer_id) REFERENCES customers(customer_id)
);
通过理解并应用这些范式规则,您可以设计出结构良好、高效且易于维护的数据库。