Python 后端基础(五):MySQL 表设计从零讲清,主键、外键、字段和业务建模怎么做
MySQL 不是只会增删改查就够了。真正做后端项目时,最重要的是能把业务对象设计成合理的数据表。本文从表、行、列、主键、外键、字段类型、范式和项目建模讲起。
【一、MySQL 在后端项目中负责什么】
MySQL 是关系型数据库,适合长期、稳定地保存结构化数据。
在 Python 后端项目中,MySQL 常用于保存:
- 用户账号
- 角色权限
- 商品信息
- 订单记录
- 支付流水
- 文章内容
- 任务状态
- 文件元数据
- AI 调用日志
- 知识库文档信息
Redis 更像高速缓存,MySQL 更像正式账本。
【二、表、行、列怎么理解】
可以把 MySQL 表理解成 Excel。
表 table:一类数据,比如 users
行 row:一条记录,比如一个用户
列 column:一个字段,比如 email、password_hash
例子:
sql
CREATE TABLE users (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(255) NOT NULL UNIQUE,
password_hash VARCHAR(255) NOT NULL,
created_at DATETIME NOT NULL
);
这里的 `users` 是用户表,每一行是一个用户,每一列是用户的一个属性。
【三、主键怎么设计】
主键是每条记录的唯一标识。
常见选择:
id BIGINT PRIMARY KEY AUTO_INCREMENT
为什么不用用户名或邮箱做主键?
因为用户名和邮箱属于业务字段,未来可能修改;主键最好稳定,不随业务变化而变化。
常见主键方案:
- 自增整数 id:简单、查询快,适合多数单体项目。
- UUID:分布式系统更方便,但长度更大,索引成本更高。
- 雪花 ID:适合分布式高并发业务。
初学项目用自增 id 就够了。
【四、外键是什么】
外键用来表达表和表之间的关系。
比如一个用户可以有多个订单:
sql
CREATE TABLE orders (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
user_id BIGINT NOT NULL,
total_amount DECIMAL(10, 2) NOT NULL,
status VARCHAR(20) NOT NULL,
created_at DATETIME NOT NULL,
FOREIGN KEY (user_id) REFERENCES users(id)
);
`orders.user_id` 指向 `users.id`,表示这个订单属于哪个用户。
真实项目里,有些团队不强制使用数据库外键,而是在业务代码里维护关系。但逻辑上你必须知道:谁属于谁,谁关联谁。
【五、字段类型怎么选】
常见字段类型:
| 类型 | 用途 |
|---|---|
| INT / BIGINT | 数字 id、数量 |
| VARCHAR | 用户名、邮箱、标题 |
| TEXT | 长文本内容 |
| DECIMAL | 金额 |
| DATETIME | 创建时间、更新时间 |
| BOOLEAN / TINYINT | 是否启用、是否删除 |
| JSON | 半结构化配置,不适合滥用 |
金额不要用 FLOAT,因为浮点数有精度问题。金额一般用 `DECIMAL(10,2)`。
【六、常见通用字段】
后端项目里的核心表通常会加:
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
deleted_at DATETIME NULL
或者:
is_deleted TINYINT NOT NULL DEFAULT 0
作用:
- `created_at`:什么时候创建。
- `updated_at`:什么时候更新。
- `deleted_at` / `is_deleted`:软删除,保留历史记录。
订单、支付、日志这类数据通常不能随便物理删除。
【七、范式是什么】
范式可以简单理解成“减少重复数据,保证数据关系清楚”的设计原则。
例如不要在订单表里直接保存用户所有信息:
orders 表:
id, user_id, username, user_email, user_address, ...
更合理的是:
users 表保存用户信息
orders 表保存订单信息,并用 user_id 关联 users
但也不是范式越高越好。真实项目中,为了查询效率,可能会做适当冗余。
比如订单表保存 `receiver_name`、`receiver_phone`、`receiver_address` 是合理的,因为下单后收货信息应该固化,不能因为用户后来改地址就影响历史订单。
【八、表设计的思考步骤】
设计表时先问:
1. 系统有哪些核心对象?
2. 每个对象有哪些字段?
3. 对象之间是什么关系?
4. 哪些字段必须唯一?
5. 哪些字段经常用于查询?
6. 哪些操作需要事务?
7. 哪些数据不能物理删除?
比如 RAG 知识库项目:
users:用户
knowledge_bases:知识库
documents:文档
document_chunks:文档切片
chat_sessions:对话会话
chat_messages:消息
llm_call_logs:模型调用日志
这就比只建一张 `data` 表清晰得多。
【九、常见坑】
- 所有字段都用 VARCHAR。
- 金额用 FLOAT。
- 没有创建时间和更新时间。
- 该唯一的字段没有加唯一约束,比如邮箱。
- 表之间关系不清楚,到处重复存数据。
- 业务状态用中文字符串,后期维护困难。
- 物理删除重要业务数据,无法审计。
更多推荐

所有评论(0)