选对字段类型是核心设计决策:整数按需取最小且优先无符号;金融数据必用decimal;字符串首选varchar,定长极短字段可用char;时间统一用datetime;枚举改用tinyint+字典表。

选对字段类型不是细节问题,而是直接影响存储效率、查询性能和数据准确性的核心设计决策。关键不在“能用”,而在“刚好够用”——小一点更省空间,确定性更强更少出错。
整数类型:按需取最小,无符号优先
整数类型要从 TINYINT → SMALLINT → MEDIUMINT → INT → BIGINT 逐级往上选,只用能满足业务最大值的最小类型。
- 状态、开关、性别、年级等:用 TINYINT UNSIGNED(0~255),1 字节,快且省
- 用户 ID、订单号(预估不超 42 亿):用 INT UNSIGNED(0~4294967295),4 字节,通用稳妥
- 高频写入的超大规模表主键(如日志、消息ID):用 BIGINT UNSIGNED,避免未来溢出
- 明确不存负数的字段,一律加 UNSIGNED,既扩大正数范围,又防止误插负值
- 别用 INT(11) 这类带显示宽度的写法——它不影响存储和取值,纯属历史遗留显示控制,可忽略
小数类型:金融必用 DECIMAL,浮点仅限科学场景
FLOAT 和 DOUBLE 存的是近似值,计算时有精度漂移风险;DECIMAL 存的是精确十进制数,适合所有需要保真的场景。
- 金额、利率、积分余额、单价等:必须用 DECIMAL(M,D),例如
DECIMAL(12,2)表示最多 12 位数字、含 2 位小数 - 不要用 FLOAT 存金额,
0.1 + 0.2可能得0.30000001,线上已踩过坑 - 温度、传感器读数、比例系数等允许误差的场景:可用 FLOAT 或 DOUBLE,节省空间且足够
- M 和 D 要合理设定:D 决定小数精度,M 决定总位数;过大浪费空间(DECIMAL 按每 9 位占 4 字节计算)
字符串类型:VARCHAR 是主力,CHAR 仅用于极短定长字段
VARCHAR 更灵活、更省空间;CHAR 仅在长度固定且极短(≤ 5 字符)、更新频繁时才略占优势。
- 用户名、地址、标题、描述等:统一用 VARCHAR(N),N 设为业务实际最长需求+10%余量,避免盲目设 255
- 国家代码(如 CN、US)、性别码(M/F)、状态码(active/inactive):可用 CHAR(2) 或 CHAR(10),定长高效
- 禁止用 VARCHAR(255) 存所有字符串——字段过大会拖慢索引效率,也掩盖真实业务约束
- 大文本(如文章正文、JSON 报文):不放主表,拆到独立表用 TEXT 或 MEDIUMTEXT,主表只留 ID 关联
时间与特殊类型:DATETIME 为主,慎用 TIMESTAMP 和 ENUM
DATETIME 稳定、范围广、不自动时区转换;TIMESTAMP 有 2038 年限制且行为隐式,ENUM 易引发迁移和扩展问题。
- 创建时间、更新时间、业务日期(如订单日期、生日):统一用 DATETIME
- 避免用 TIMESTAMP——它依赖系统时区,插入时自动转 UTC,查询时再转回本地,逻辑难追踪,且 2038 年后失效
- 状态、类型、分类等有限枚举值:不用 ENUM,改用 TINYINT UNSIGNED + 字典表或注释说明,便于后期增删和跨语言适配
- 需要结构化嵌套数据(如用户配置、设备参数):MySQL 5.7+ 可用 JSON 类型,支持校验和索引,比 TEXT 更安全可控
- 手机号、IP 地址等:手机号用 VARCHAR(20)(兼容国际号),IPv4 用 INT UNSIGNED 配合
INET_ATON()/INET_NTOA()










