贴吧式
枚举字段到底该存 int 还是 varchar?一个被吵了十年的表设计分歧
帖子正文与楼层回复。
楼主 陈亦舟-962
数据库设计枚举表设计DBAMySQL
先给结论:我的默认倾向是用 varchar 存可读的枚举字符串,只有在「高基数、纯内部状态机、需要按值做范围/排序、且永不对外展示」的少数场景才退回 int。下面把这件事的分歧摊开聊聊。
【背景】 做了 10 年 DBA,表设计评审里被吵得最凶、且每次都能吵半小时的,就是「状态/类型字段到底存 1/2/3 还是存 'PAID'/'REFUNDED'」。业务方和开发两边各执一词:开发觉得 int 省空间、好建索引、好做位运算;后端语言团队觉得字符串可读、跨语言不踩坑。而 DBA 这边其实最纠结——因为这个选择一旦定下来,迁移成本极高:从 int 改 varchar 要动数据、动索引、动所有 SQL;反过来 varchar 改 int 同样要全量刷数据。所以它不是一个「写代码时随手定」的细节,而是建表那一刻就要想清楚的契约。
【常见分歧 / 几种做法】
- int + 字典表派:
status TINYINT配一张status_dict,省空间、索引紧凑,认为「可读性交给应用层枚举」。 - varchar 字符串派:
status VARCHAR(16)直接存'PAID',可读、自解释,认为「数据库里看到数据本身就该能看懂」。 - int + 应用层常量派:存 int 但不建字典表,靠代码里的 enum 映射,灵活但 DBA 排查时一脸懵。
- 位图/多状态合并派:把「已付费 + 已发货 + 已评价」压成一个 bitmask int,省字段但彻底牺牲可读性与可统计性。
【我的倾向与理由】 我默认选 varchar,核心是三条:
- 可读性即运维成本:线上排查时
SELECT status FROM t_order直接出 'REFUNDED' 和出一串 3,是两个世界。DBA 半夜看 dump、看 binlog、做对账,字符串能救命。 - 演进与跨语言:int 的语义完全靠应用层约定,换个语言、换个团队,1 到底是不是 PAID 全靠猜;字符串自带语义,新团队接入、跨服务对接、导出到报表都零歧义。
- 现代硬件下那点空间不值钱:TINYINT 省的那 15 字节,在 SSD 与缓冲池面前几乎可以忽略;而「可读 + 可演进」带来的长期维护收益远大于此。唯一我会退回 int 的,是那种基数极高、纯内部流转、需要
BETWEEN/ORDER BY数值语义的状态机,或者明确要做位运算的标记位——这种我会在字段注释里写死每一位的含义。
【想听大家怎么说】
- 你们团队现在的主流是哪种?为什么?踩过 int→varchar 或反向迁移的坑吗,代价多大?
- 多状态合并(bitmask)你们用不用?在什么场景下真的划算?
- 如果让我给「新表一律用 varchar 存枚举」定一条团队规范,你会在哪些字段上开例外?
- 有没有「当初选了 int 省了空间,结果排查/迁移时加倍还回去」的真实案例?
想听听不同规模、不同语言栈的团队在什么场景下怎么选,以及你们是怎么给这个选择做「可逆性」兜底的。
赞 0 · 收藏 0 · 楼层 0
楼层
#1
作者
楼层正文
还没有人回复。