2. Schema 设计原则:命名规范、字段类型选择、版本号管理、兼容性设计

好,咱们进入正题。Schema 设计这事儿,看着简单,但坑是真不少。我见过太多系统,上线半年后因为 Schema 设计不合理,改又不敢改,推又推不动,最后只能硬扛着。

说白了,Schema 就是数据的骨架。骨架歪了,后面长多少肉都别扭。今天我把几个核心原则掰开揉碎讲清楚,都是我用真金白银换来的经验。

2.1 命名规范:别让名字成为灾难

命名这事,我一开始也觉得无所谓。直到有一次,我在一个遗留系统里看到 user_name、username、userName 三个字段同时存在,分别代表三个不同的业务含义……嗯,那感觉,就像吃面发现三根面条是三种颜色。

我曾经踩过的坑: 团队没有统一命名规范,结果数据同步时,A 系统叫 create_time,B 系统叫 created_at,C 系统叫 gmt_create。为了对齐这三个字段,我写了整整两天的 ETL 脚本。

命名规范,我建议你记住三条铁律:

  • 全小写 + 下划线分隔:order_id 而不是 orderId 或 OrderID。为什么?因为不同数据库对大小写敏感程度不一样,下划线是最大公约数。
  • 业务含义优先:user_registration_date 比 reg_dt 好一万倍。别为了省几个字符,让后人猜谜语。
  • 禁止保留字:别用 order、group、select 做字段名。我见过有人用 order 做表名,每次查询都要加反引号,看着就累。
场景 推荐命名 不推荐命名
用户ID user_id uid、userId、UserID
创建时间 created_at create_time、ct、gmt_create
订单状态 order_status status、ord_st、flag
是否删除 is_deleted del、delete_flag、valid
我的小技巧: 在团队里搞一个命名词典,把常用字段的命名固定下来。新人来了直接查,不用猜。我之前的团队用 Confluence 维护这个词典,效果不错。

2.2 字段类型选择:选错了就是给自己挖坑

字段类型这事,我见过最离谱的——有人用 VARCHAR(255) 存时间戳。你想想看,存进去的是字符串,查出来还得 CAST 一下,性能能好吗?

我个人习惯,字段类型选择遵循三个原则:

  1. 用对类型,别用万能类型:时间就用 TIMESTAMP 或 DATETIME,数字就用 INT 或 BIGINT,别什么都往 VARCHAR 里塞。
  2. 精度够用就行:存年龄用 TINYINT 就够了,别用 INT。存金额用 DECIMAL(10,2),别用 FLOAT——浮点数有精度问题,算账会差一分钱。
  3. 考虑未来扩展:状态字段别用 INT 存 0 和 1,万一以后要加个「待审核」状态呢?用 VARCHAR 存枚举值,或者用 TINYINT 预留几位。

核心原则: 字段类型的选择,决定了你的数据能做什么、不能做什么。选对了,查询快、存储省、维护简单。选错了,后面全是补丁。

举个例子,存用户性别:

  • 错误做法:gender INT(0 男 1 女 2 未知),你永远记不住 0 代表什么。
  • 推荐做法:gender VARCHAR(10),存 male、female、unknown,一目了然。
  • 更优做法:用枚举类型 ENUM('male', 'female', 'unknown'),既清晰又节省空间。

2.3 版本号管理:给 Schema 上个身份证

版本号这事,我一开始也没当回事。直到有一次,生产环境出了 Bug,我排查了半天才发现——代码是新的,但数据库 Schema 还是旧的。字段对不上,数据全乱了。

从那以后,我强制要求每个 Schema 都必须带版本号。怎么管?我建议这样做:

  • 用 schema_version 表:单独建一张表,记录当前 Schema 的版本号、变更时间、变更描述。
  • 版本号格式:用语义化版本 v1.2.3,主版本号(不兼容变更)、次版本号(向下兼容的新功能)、修订号(Bug 修复)。
  • 变更脚本统一管理:每次 Schema 变更都写一个 SQL 脚本,按版本号命名,比如 V1.2.3__add_user_email.sql。
注意: 版本号不是摆设。我见过有人改了 Schema 但不更新版本号,结果回滚时根本不知道回滚到哪个版本。版本号是 Schema 的身份证,丢了就麻烦了。

举个例子,版本号管理流程:

-- 创建版本管理表
CREATE TABLE schema_version (
    version VARCHAR(20) NOT NULL,
    description VARCHAR(255),
    applied_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 每次变更后插入一条记录
INSERT INTO schema_version (version, description)
VALUES ('v1.2.3', '新增用户邮箱字段');

2.4 兼容性设计:向前兼容是底线

兼容性设计,说白了就是——你改了 Schema,别让老数据、老代码崩了。我见过最惨的一次,有人把字段类型从 INT 改成 VARCHAR,结果所有历史数据都读不出来了。

兼容性设计,我总结了几条硬规则:

  • 只加不减:新版本可以加字段,但别删字段。老代码可能还在用呢。
  • 只放宽不收紧:字段长度可以从 VARCHAR(50) 改成 VARCHAR(100),但别反过来。类型可以从 INT 改成 BIGINT,但别从 BIGINT 改成 INT。
  • 新字段要有默认值:加字段时,给个默认值。不然老数据读出来是 NULL,代码没处理 NULL 就崩了。
  • 废弃字段先标记后删除:想删字段?先标记为 deprecated,等所有依赖都清理干净了,再动手删。
我的经验: 兼容性设计不是技术问题,是沟通问题。每次 Schema 变更前,先跟所有相关团队打个招呼,确认没有依赖。我吃过一次亏后,现在变更前都会发邮件通知,等 24 小时确认没问题再动手。

来看一个兼容性设计的例子:

-- 旧版本:用户表
CREATE TABLE users (
    user_id INT PRIMARY KEY,
    username VARCHAR(50) NOT NULL
);

-- 新版本:加字段,但不影响老数据
ALTER TABLE users ADD COLUMN email VARCHAR(100) DEFAULT '' NOT NULL;
-- 注意:加了 DEFAULT '',老数据自动填充空字符串,不会出现 NULL

2.5 知识体系总览

说了这么多,咱们用一张图把 Schema 设计的核心逻辑串起来。你一看就明白了。

Schema 设计核心原则 Schema 设计 命名规范 字段类型选择 版本号管理 兼容性设计 全小写下划线 业务含义优先 禁止保留字 用对类型 精度够用 考虑扩展 版本管理表 语义化版本 脚本统一管理 只加不减 只放宽不收紧 默认值 + 标记废弃 核心:命名清晰 + 类型准确 + 版本可追溯 + 变更兼容

这张图把四个核心原则串起来了。你看,命名规范是基础,字段类型是骨架,版本号是身份证,兼容性是安。四个缺一不可。

好了,Schema 设计原则就讲到这里。记住一句话:好的 Schema 设计,是让后来者看着舒服、改着放心、用着顺手。别让你的 Schema 成为别人的噩梦。