我工作头几年有个特别深的体会:MySQL 安装教程、数据库命令大全这类内容随手就能搜到,但一个人从“会写增删改查”到“能独立设计一张合理的业务表”,中间其实缺了一大环。这一环就是 MySQL 库表设计规范。很多新人在建表时总觉得“表嘛,能存下数据不就行了”,但等项目跑起来、数据量上来、报表要统计、索引要优化的时候,当初建表时偷的懒全都会加倍还回来。
这篇内容就是要解决这个问题。我会从需求梳理、命名规范、字段类型、索引设计到完整案例,把一套可以直接照着抄的库表设计流程讲透。默认你用的是 MySQL 8.0、InnoDB 引擎,字符集统一 utf8mb4。如果你是刚入行的后端开发、在校学生,或者准备面试但被问到“你怎么设计一张表”就发怵,这篇应该能给你一个比较完整的框架。
1. 开工之前先这样拆需求:别让表结构输在起跑线
1.1 需求落到表之前,先回答四个问题
我见过很多新人拿到需求后的第一反应是:打开 navicat,新建表,凭感觉敲字段。这个流程基本一定会出问题。正确做法是先别碰 SQL,把需求里的“数据”拆一遍,至少回答清楚四件事。
第一,这个表的核心实体是谁。用户、订单、课程、商品,这些才叫实体,一个核心实体对应一张主表。比如订单和订单明细是两个不同粒度的东西,硬塞到一张大宽表里,后面加商品数量、改价格、查明细时就是灾难。第二,每个字段是不是原子值。手机号、邮箱、省市区这些不能混在一个字段里,后期要按某个维度统计时你会想哭。第三,哪些字段会被查询、排序、去重或作为唯一标识。这些字段基本都要有对应的索引方案,决定了字段类型不能乱选。第四,数据量级和写入速度有没有预期。每日百万订单和每日几千订单,建表时的主键策略、分区规划完全不同。
有一个很常见的反例,就是新人把订单主表设计成包含商品名称、商品数量、商品单价、收货人详细地址等等的大宽表。感觉查订单时一条 SQL 全出来了,特别省事。可一旦用户一个订单下三件商品,你打算怎么存?复制三行订单行还是三个字段平铺?前者产生大量冗余主单数据,后者终有一天要加第四件商品时只能改表。正确思路是把订单拆成 order_main 和 order_item 两张表,主表存一次下单动作的公共信息,明细表存每条商品的独立信息。
1.2 命名规范:一次定好,减少以后的“回车”
命名这件事看起来是洁癖,其实是工程问题。统一命名最大的价值是:三个月后你自己回来看表,或者别的同事接手时,不用猜字段含义。
我建议一套比较通用的规范,你们可以按团队情况微调,但一定要定下来:
- 表名、字段名全部使用小写字母加下划线,不要用驼峰。
userId这种命名在 Linux 环境、不同客户端工具之间容易踩大小写敏感的坑,全部小写最稳。 - 表名建议单数,因为
students和student混在一起反而更乱。关键是全团队统一,不要一半表用单数一半用复数。 - 用业务模块前缀分类,比如用户模块
user_info、user_address,订单模块order_main、order_item,一眼就知道这张表是干嘛的。 - 不要用 MySQL 保留字做表名或字段名。经典翻车就是把订单表命名成
order,然后每个 SQL 都得写反引号,SELECT * FROMorder``,丑且容易埋雷。改成order_main或者order_info,瞬间清净。 - 字段命名要能表达业务含义,
name太泛,user_name就好很多。时间字段统一create_time、update_time,不要这张表写created_at,那张表写gmt_created。 - 索引命名也要统一:普通索引
idx_字段_字段,唯一索引uk_字段_字段。例如 `idx_user_create_time
