适用人群:后端开发者、全栈开发者
学习时长:约1-2天
数据库:MySQL/PostgreSQL
重要程度:★★★★☆(后端核心技能)
一、数据库设计原则
| 原则 | 说明 |
|---|
| 范式化 | 减少数据冗余(1NF/2NF/3NF) |
| 适当反范式化 | 为性能适当冗余 |
| 命名规范 | 表名小写下划线,字段名小写下划线 |
| 主键设计 | 自增ID或UUID |
| 索引设计 | 为常用查询字段建索引 |
二、命名规范
-- 表名:小写下划线,复数形式
users
user_profiles
order_items
-- 字段名:小写下划线
user_name
created_at
is_deleted
-- 主键:id
id
-- 外键:表名单数_id
user_id
category_id
-- 时间字段
created_at
updated_at
deleted_at(软删除)
-- 布尔字段
is_active
is_deleted
has_paid
三、常用表结构
3.1 用户表
CREATE TABLE users (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(50) NOT NULL UNIQUE,
email VARCHAR(100) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
nickname VARCHAR(50),
avatar VARCHAR(255),
phone VARCHAR(20),
role ENUM('admin', 'editor', 'user') DEFAULT 'user',
is_active BOOLEAN DEFAULT TRUE,
email_verified_at TIMESTAMP NULL,
last_login_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL,
INDEX idx_email (email),
INDEX idx_phone (phone),
INDEX idx_role (role),
INDEX idx_is_active (is_active)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
3.2 文章表
CREATE TABLE posts (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
title VARCHAR(200) NOT NULL,
slug VARCHAR(200) NOT NULL UNIQUE,
content TEXT NOT NULL,
excerpt VARCHAR(500),
cover_image VARCHAR(255),
status ENUM('draft', 'published', 'archived') DEFAULT 'draft',
views INT UNSIGNED DEFAULT 0,
likes INT UNSIGNED DEFAULT 0,
author_id BIGINT UNSIGNED NOT NULL,
category_id BIGINT UNSIGNED,
published_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL,
FOREIGN KEY (author_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (category_id) REFERENCES categories(id) ON DELETE SET NULL,
INDEX idx_slug (slug),
INDEX idx_status (status),
INDEX idx_author (author_id),
INDEX idx_category (category_id),
INDEX idx_published_at (published_at),
FULLTEXT INDEX ft_title_content (title, content)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
3.3 订单表
CREATE TABLE orders (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
order_no VARCHAR(32) NOT NULL UNIQUE,
user_id BIGINT UNSIGNED NOT NULL,
total_amount DECIMAL(10, 2) NOT NULL,
discount_amount DECIMAL(10, 2) DEFAULT 0,
payable_amount DECIMAL(10, 2) NOT NULL,
status ENUM('pending', 'paid', 'shipped', 'completed', 'cancelled') DEFAULT 'pending',
payment_method VARCHAR(20),
payment_no VARCHAR(64),
address_snapshot JSON NOT NULL,
remark VARCHAR(500),
paid_at TIMESTAMP NULL,
shipped_at TIMESTAMP NULL,
completed_at TIMESTAMP NULL,
cancelled_at TIMESTAMP NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES users(id),
INDEX idx_order_no (order_no),
INDEX idx_user_id (user_id),
INDEX idx_status (status),
INDEX idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
3.4 订单商品表
CREATE TABLE order_items (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
order_id BIGINT UNSIGNED NOT NULL,
product_id BIGINT UNSIGNED NOT NULL,
product_name VARCHAR(200) NOT NULL,
product_image VARCHAR(255),
sku_id BIGINT UNSIGNED,
price DECIMAL(10, 2) NOT NULL,
quantity INT UNSIGNED NOT NULL,
subtotal DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (order_id) REFERENCES orders(id) ON DELETE CASCADE,
FOREIGN KEY (product_id) REFERENCES products(id),
INDEX idx_order_id (order_id),
INDEX idx_product_id (product_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
3.5 商品表
CREATE TABLE products (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(200) NOT NULL,
slug VARCHAR(200) NOT NULL UNIQUE,
description TEXT,
price DECIMAL(10, 2) NOT NULL,
original_price DECIMAL(10, 2),
stock INT UNSIGNED NOT NULL DEFAULT 0,
sales INT UNSIGNED DEFAULT 0,
category_id BIGINT UNSIGNED,
brand_id BIGINT UNSIGNED,
cover_image VARCHAR(255),
images JSON,
specs JSON,
status ENUM('on_sale', 'off_sale', 'sold_out') DEFAULT 'on_sale',
sort_order INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL,
FOREIGN KEY (category_id) REFERENCES categories(id),
INDEX idx_slug (slug),
INDEX idx_category (category_id),
INDEX idx_brand (brand_id),
INDEX idx_status (status),
INDEX idx_price (price),
INDEX idx_sales (sales),
FULLTEXT INDEX ft_name_desc (name, description)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
3.6 分类表
CREATE TABLE categories (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL,
slug VARCHAR(50) NOT NULL UNIQUE,
parent_id BIGINT UNSIGNED DEFAULT 0,
icon VARCHAR(255),
description VARCHAR(200),
sort_order INT DEFAULT 0,
is_active BOOLEAN DEFAULT TRUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_parent (parent_id),
INDEX idx_slug (slug),
INDEX idx_sort (sort_order)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
3.7 标签表
CREATE TABLE tags (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(50) NOT NULL UNIQUE,
slug VARCHAR(50) NOT NULL UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- 文章标签关联表(多对多)
CREATE TABLE post_tags (
post_id BIGINT UNSIGNED NOT NULL,
tag_id BIGINT UNSIGNED NOT NULL,
PRIMARY KEY (post_id, tag_id),
FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
3.8 评论表
CREATE TABLE comments (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
post_id BIGINT UNSIGNED NOT NULL,
user_id BIGINT UNSIGNED,
parent_id BIGINT UNSIGNED,
content TEXT NOT NULL,
status ENUM('pending', 'approved', 'rejected') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (post_id) REFERENCES posts(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL,
FOREIGN KEY (parent_id) REFERENCES comments(id) ON DELETE CASCADE,
INDEX idx_post_status (post_id, status),
INDEX idx_user (user_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
四、索引设计原则
-- 1. 为WHERE条件字段建索引
SELECT * FROM users WHERE email = 'test@example.com';
-- 索引:INDEX idx_email (email)
-- 2. 为JOIN字段建索引
SELECT * FROM posts p JOIN users u ON p.author_id = u.id;
-- 索引:INDEX idx_author (author_id)
-- 3. 为ORDER BY字段建索引
SELECT * FROM posts ORDER BY published_at DESC;
-- 索引:INDEX idx_published_at (published_at)
-- 4. 联合索引遵循最左前缀
SELECT * FROM posts WHERE status = 'published' AND category_id = 1;
-- 索引:INDEX idx_status_category (status, category_id)
-- 5. 避免过度索引
-- 每个索引都会占用存储空间,影响写入性能
五、常见设计模式
5.1 软删除
-- 使用deleted_at字段实现软删除
ALTER TABLE users ADD COLUMN deleted_at TIMESTAMP NULL;
-- 查询时过滤已删除数据
SELECT * FROM users WHERE deleted_at IS NULL;
-- 删除操作
UPDATE users SET deleted_at = NOW() WHERE id = 1;
-- 恢复
UPDATE users SET deleted_at = NULL WHERE id = 1;
5.2 树形结构
-- 方式1:邻接表(parent_id)
CREATE TABLE categories (
id INT PRIMARY KEY,
name VARCHAR(50),
parent_id INT DEFAULT 0
);
-- 查询子分类
SELECT * FROM categories WHERE parent_id = 1;
-- 方式2:路径枚举
CREATE TABLE categories (
id INT PRIMARY KEY,
name VARCHAR(50),
path VARCHAR(255) -- 如:/1/2/3/
);
-- 查询所有子分类
SELECT * FROM categories WHERE path LIKE '/1/%';
5.3 多态关联
-- 评论可以属于文章或商品
CREATE TABLE comments (
id INT PRIMARY KEY,
commentable_type VARCHAR(50), -- 'post' 或 'product'
commentable_id INT,
content TEXT,
INDEX idx_commentable (commentable_type, commentable_id)
);
-- 查询文章评论
SELECT * FROM comments
WHERE commentable_type = 'post' AND commentable_id = 123;
六、性能优化
-- 1. 使用EXPLAIN分析查询
EXPLAIN SELECT * FROM posts WHERE status = 'published';
-- 2. 避免SELECT *
SELECT id, title, slug FROM posts WHERE status = 'published';
-- 3. 分页优化
-- 慢:OFFSET大的时候
SELECT * FROM posts LIMIT 10 OFFSET 10000;
-- 快:使用游标分页
SELECT * FROM posts WHERE id > 10000 LIMIT 10;
-- 4. 批量插入
INSERT INTO users (username, email) VALUES
('user1', 'user1@example.com'),
('user2', 'user2@example.com'),
('user3', 'user3@example.com');
-- 5. 使用覆盖索引
-- 索引包含查询的所有字段,不需要回表
SELECT username, email FROM users WHERE username = '张三';
学习建议
- 先理解范式化,掌握1NF/2NF/3NF
- 学会命名规范,代码整洁的基础
- 掌握索引设计,性能优化的关键
- 理解常见设计模式,软删除、树形结构、多态关联
- 实际项目中练习,从简单表结构开始
下一步学习