← 返回文章列表
数据库·1188 次阅读

MySQL 字段类型怎么选:一张表看懂,附血泪教训

上个月接手一个老系统,发现订单表的金额字段是 FLOAT。对账差了三分钱,财务排查了一下午。FLOAT 的精度问题教科书写得明明白白,但总有人(包括三年前的我自己)觉得"应该没事"。

建表时多花三十秒选类型,胜过半年后通宵对账。这篇是我的选型手册。

数字类型

类型 字节 适用场景
TINYINT 1 状态、性别、布尔(0-255)
INT 4 主键、普通计数(±21 亿)
BIGINT 8 大表主键、雪花 ID
DECIMAL(M,D) 变长 金额唯一选择
FLOAT/DOUBLE 4/8 科学计算,别存钱

金额为什么必须 DECIMAL:FLOAT 是二进制浮点,0.1 + 0.2 ≠ 0.3 那个经典问题就是它。DECIMAL 按十进制精确存储,财务场景没有第二种选择:

-- ✅ 金额标准姿势:总共 10 位,小数 2 位
amount DECIMAL(10, 2) NOT NULL DEFAULT 0.00

-- ❌ 等着对账对到天亮
amount FLOAT

主键建议 INT UNSIGNED 或 BIGINT UNSIGNED:无符号让正数范围翻倍,而且主键本来就没有负数。

字符串类型

类型 适用场景
VARCHAR(n) 变长字符串,n 按业务实际长度定
CHAR(n) 定长,适合 MD5(32 位)、手机号的场景
TEXT 家族 大文本:文章内容、JSON

VARCHAR(n) 的 n 不是越大越好:虽然存储按实际长度,但内存排序和临时表按声明长度分配。VARCHAR(255) 一把梭的人,sort buffer 哭给你看。用户名就 VARCHAR(32),标题 VARCHAR(128),别偷懒。

CHAR vs VARCHAR:CHAR 是定长,存 'abc' 到 CHAR(10) 也占 10 个字符空间。只有长度严格固定的场景(MD5、国家码)才用 CHAR,其他一律 VARCHAR。

TEXT 的坑:TEXT 列不能建普通索引(只能前缀索引)、查询时不能进内存临时表(走磁盘)。文章内容该用还得用,但别把高频查询条件的字段定成 TEXT。

时间类型:别再用 INT 存时间戳了

类型 字节 范围 特点
DATETIME 8(5.6.4+ 为 5 + 小数) 1000-9999 年 不涉及时区,存什么读什么
TIMESTAMP 4 1970-2038 年 随时区转换,2038 年溢出
DATE / TIME 3/3 - 只存日期/时间

我的规则:

  • 业务时间用 DATETIME:创建时间、更新时间。范围无上限,不受时区影响
  • TIMESTAMP 只剩一个优势:跨时区系统自动转换。绝大多数业务用不上,还背着 2038 炸弹
  • 千万别用 INT 存时间戳:可读性为零(看到 1565424000 你得拿计算器),还丢了所有日期函数的便利
-- 标准姿势
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP

ON UPDATE CURRENT_TIMESTAMP 让 updated_at 在每次更新时自动刷新,省掉应用层维护。

JSON 类型(MySQL 5.7+)

存结构不固定的扩展字段(商品属性、表单配置):

attrs JSON

好处是有 JSON 校验、可以用 -> 和 ->> 查询内部字段、还能对特定路径建虚拟列索引。但记住:JSON 字段是扩展位的补充,不是表结构的替代品。高频查询、需要关联的字段必须平铺成列。

枚举与集合

ENUM('PUBLISHED', 'DRAFT') 看着美好,实际项目里我基本不用:加枚举值要 ALTER TABLE、迁移工具兼容性差、ORM 支持参差不齐。状态字段用 TINYINT + 代码里定义常量是更灵活的实践:

status TINYINT NOT NULL DEFAULT 0 COMMENT '0草稿 1已发布 2已下架'

COMMENT 一定要写,这是给三个月后的自己看的。

我的建表检查清单

  • 主键:INT/BIGINT UNSIGNED AUTO_INCREMENT
  • 金额:DECIMAL(10,2),杜绝 FLOAT
  • 时间:DATETIME + 自动更新,杜绝 INT 时间戳
  • 字符串:VARCHAR(n),n 按真实业务长度,不偷懒用 255
  • 状态:TINYINT + COMMENT 写清取值含义
  • 大文本才用 TEXT,查询条件字段绝不用 TEXT
  • 字符集:utf8mb4(utf8 在 MySQL 里是残血版,存不了 emoji)

小结

  • 金额 DECIMAL、时间 DATETIME、状态 TINYINT,三件套背下来
  • VARCHAR 长度按业务定,sort buffer 会感谢你
  • TEXT 别当查询条件,JSON 别当表结构
  • 每个字段写 COMMENT,每个表用 utf8mb4

数据库类型选择是典型的"五分钟学习,五年受益"的知识。建表前把这篇翻出来对照一遍,能避开 90% 的低级坑。

看到这里了?如果这篇文章帮到过你

请我喝瓶可乐就好 🥤

收款码

评论0 条

还没有评论,来抢沙发~

发表评论

评论需审核后显示

© 2026 许冬博客 · 专注 JS 技术分享

·RSS 订阅·Powered by Nuxt 4