MySQL 数据类型
数值类型
整数按存储宽度分档:TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,大约占用 1、2、3、4、8 字节。主键、用户 ID 用 BIGINT 更稳妥,避免业务增长后改列类型。
INT(10) 里的 10 是显示宽度,不改变取值范围。只有配合 ZEROFILL 时才会在展示时左侧补零。MySQL 8.0.17 起整数显示宽度已废弃,不要再用它表达「这个数字有几位」。
金额、汇率、精确小数用 DECIMAL(M,D)。FLOAT / DOUBLE 是二进制浮点,0.1 + 0.2 这类误差会直接进账本。FLOAT(5,2) 这种非标准声明也不建议,精度在 DECIMAL 上写清楚即可。
字符串与字符集
CHAR(N) 定长,短且长度稳定的码表适合用,例如国家码、固定宽度状态码。不足的部分会补空格,检索时再去掉尾部空格。
VARCHAR(N) 变长,多数字段的默认选择。N 是字符数,实际字节还受字符集影响:utf8mb4 最坏按 4 字节计,行长度上限会把 VARCHAR 的最大长度往下压。
字符集用 utf8mb4。MySQL 里名叫 utf8 的其实是 utf8mb3,三字节 UTF-8 存不下 emoji 和部分生僻字,写入会报错或截断。
TEXT / BLOB 适合真正的大字段。它们更容易让查询走临时表,也很难被覆盖索引带上。能拆到扩展表就拆,列表查询不要 SELECT * 把正文一并带出。
日期时间
| 类型 | 大致范围 | 存储 | 时区 |
|---|---|---|---|
| DATETIME | 1000-01-01 ~ 9999-12-31 | 5~8 字节(版本有关) | 存什么就是什么 |
| TIMESTAMP | 1970 ~ 2038(32 位时代) | 旧实现 4 字节 | 按会话时区转换 |
业务上的「下单时间、生日、活动开始时间」更稳妥用 DATETIME:看到的值和写入值一致,也不用提前处理 2038 年问题。
TIMESTAMP 会按时区转换,同一条记录在 +08:00 和 UTC 会话里读出来不一样。多个机房、要「跟着用户时区显示」时它有用;只是想存一个绝对时间,时区转换反而是坑。
常见选型
| 用途 | 建议 |
|---|---|
| 主键 / 用户 ID | BIGINT |
| 金额 | DECIMAL |
| 短文本 | VARCHAR + utf8mb4 |
| 长文本 | TEXT,必要时垂直拆表 |
| 业务时间 | DATETIME |
| 半结构化 | JSON |
列类型一旦写进聚簇索引和所有二级索引,后面改类型就是重建表。能在建表时选对,比上线后再 ALTER 便宜得多。