数据库设计三大范式:从需求分析到 ER 图
良好的数据库设计是系统稳定的基础。本文介绍数据库设计的基本原则。
三大范式
第一范式(1NF)
字段不可再分。
-- ❌ 违反 1NF
CREATE TABLE users (
id INT,
address VARCHAR(200) -- 地址可以再分
);
-- ✅ 符合 1NF
CREATE TABLE users (
id INT,
province VARCHAR(50),
city VARCHAR(50),
district VARCHAR(50)
);
第二范式(2NF)
非主键字段完全依赖于主键。
-- ❌ 违反 2NF
CREATE TABLE order_items (
order_id INT,
product_id INT,
product_name VARCHAR(100), -- 只依赖 product_id
quantity INT
);
-- ✅ 符合 2NF
CREATE TABLE products (
id INT PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE order_items (
order_id INT,
product_id INT,
quantity INT,
PRIMARY KEY (order_id, product_id)
);
第三范式(3NF)
非主键字段不能传递依赖于主键。
-- ❌ 违反 3NF
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
user_name VARCHAR(100), -- 依赖 user_id,不是直接依赖 id
amount DECIMAL(10,2)
);
-- ✅ 符合 3NF
CREATE TABLE users (
id INT PRIMARY KEY,
name VARCHAR(100)
);
CREATE TABLE orders (
id INT PRIMARY KEY,
user_id INT,
amount DECIMAL(10,2)
);
ER 图设计
实体
┌─────────────┐
│ User │
├─────────────┤
│ id (PK) │
│ name │
│ email │
└─────────────┘
关系
- 一对一:用户 - 身份证
- 一对多:用户 - 订单
- 多对多:用户 - 角色
表结构优化
选择合适的数据类型
-- ✅ 使用合适的数据类型
CREATE TABLE users (
id BIGINT PRIMARY KEY, -- 大表用 BIGINT
name VARCHAR(50) NOT NULL, -- 不用 CHAR
age TINYINT UNSIGNED, -- 小范围用 TINYINT
status TINYINT DEFAULT 1, -- 状态用数字
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
反范式化
适当冗余可以提升查询性能。
-- 订单表冗余用户名
CREATE TABLE orders (
id BIGINT PRIMARY KEY,
user_id BIGINT,
user_name VARCHAR(100), -- 冗余
amount DECIMAL(10,2)
);
总结
数据库设计遵循三大范式,但也要根据实际情况适当反范式化。良好的设计是系统稳定的基础。