聊聊怎么更好去设计数据库表
作为一名资深后端开发,你有没有遇到过这样的场景:接手一个新项目,看到前任同事设计的数据库表结构,简直让人怀疑人生?表名莫名其妙,字段命名混乱,关系不清不楚,查询效率低下…
这让我深刻意识到了:哪怕是一些"高级开发",也并不知道怎么去设计一个好的表结构。
于是决定和大家一起探讨如何更好的设计表结构。所有观点都是结合多年的经验得来,不一定正确,如有错误之处欢迎大家指正。
一、表名设计:第一眼就要知道是干什么的
1.1 有意义的前缀 + 清晰的表名
前缀在大型系统中是有必要的,可以区分不同业务模块,但关键是前缀要有明确含义,表名要语义清晰。
❌ 不好的命名:
DC_COURSE_TESTPAPER -- TESTPAPER是问卷还是试卷?
TB_USER_INFO -- TB前缀无意义,INFO太泛泛
T_ORDER_DTL -- DTL是detail的缩写?
DATA_TBL_001 -- 完全看不懂
✅ 好的命名:
DC_COURSE_QUESTIONNAIRES -- DC表示Distance Course远程课程系统
SYS_USER_PROFILES -- SYS表示系统核心模块
ORDER_ITEMS -- 订单商品明细
LMS_STUDENT_SCORES -- LMS表示Learning Management System
什么时候需要前缀?
- 多个业务系统共用数据库:USER_, ORDER_, PRODUCT_
- 区分不同数据类型:LOG_, CONFIG_, TEMP_
- 大型项目的模块划分:CRM_, ERP_, CMS_
1.2 用完整的英文单词而不是拼音
❌ 不好的命名:
kecheng_wenjuan -- 拼音
user_xinxi -- 中英混合
订单_items -- 中英混合
✅ 好的命名:
course_questionnaires -- 纯英文,语义清晰
user_profiles -- 纯英文
order_items -- 纯英文
原因:
- 英文是编程的通用语言,团队成员更容易理解
- 避免编码问题
1.3 表名要体现业务含义,不要只是技术实现
❌ 不好的命名:
data_table_001
temp_storage
middle_table
relation_mapping
✅ 好的命名:
student_scores -- 学生成绩
file_uploads -- 文件上传记录
course_enrollments -- 课程报名
user_preferences -- 用户偏好设置
除非是临时用的表,不参与任何业务逻辑,只是用来做数据处理或者测试。
二、字段命名:见名知意
2.1 布尔字段用 is_ 开头
❌ 不好的命名:
active -- 是激活还是活跃?
delete -- 删除状态还是删除动作?
flag -- 什么标志?
✅ 好的命名:
is_active -- 是否激活
is_deleted -- 是否已删除
is_verified -- 是否已验证
用 is_ 开头的好处:
- 一眼就能看出是布尔值 - 看到 is_active 就知道这个字段要么是 true 要么是 false
- 避免歧义 - 像 active 这样的名字,你搞不清楚它表示的是状态还是动作
- 代码可读性更好 - 写代码的时候,if (user.is_active) 比 if (user.active) 更容易理解
2.2 时间字段统一后缀
❌ 不好的命名:
create_time
update_date
delete_at
register_datetime
✅ 好的命名:
created_at -- 创建时间
updated_at -- 更新时间
deleted_at -- 删除时间
registered_at -- 注册时间
好处:
- 一眼就能看出是时间字段
- 避免命名混乱
- _at 在英语里表示"在某个时间点",比 _time 更准确
- 特别推荐用 deleted_at 做逻辑删除字段,能看出来删除时间,支持数据恢复
2.3 外键字段统一 _id 后缀
❌ 不好的命名:
user -- 这是用户ID还是用户对象?
course -- 课程ID?
teacher_key -- 什么key?
✅ 好的命名:
user_id -- 用户ID
course_id -- 课程ID
teacher_id -- 教师ID
2.4 额外的经验
除了基本的命名规范,还有一些实用的经验:
- 逻辑删除用时间字段 - 用 deleted_at 比 is_deleted 好,能看出来删除时间,支持数据恢复和历史追踪
- 状态字段用枚举 - 不要用数字 1、2、3 表示状态,用 status 字段,值用 ‘pending’、‘approved’、‘rejected’ 这样的英文单词
- 金额字段用 decimal - 不要用 float 或 double,用 decimal(10,2) 这样的类型,避免浮点数精度问题
- 密码字段要加密 - 密码字段名用 password_hash 或 encrypted_password,不要直接叫 password
- 软删除要加索引 - 如果经常查询未删除的数据,给 deleted_at 字段加索引,提高查询性能
三、表结构设计:关系清晰、适度冗余
3.1 一对多关系:外键放在多的一边
让我们用用户和订单的业务关系来举例:
用户表 (users):
CREATE TABLE users (id BIGINT PRIMARY KEY,username VARCHAR(50),email VARCHAR(100),created_at TIMESTAMP
);
订单表 (orders):
CREATE TABLE orders (id BIGINT PRIMARY KEY,user_id BIGINT, -- 外键放在多的一边order_no VARCHAR(32),total_amount DECIMAL(<