在mysql建表时,数据类型的选择直接影响数据库的存储成本和运行性能,很多线上问题都源于建表时随意选择数据类型,要么用过大的类型浪费存储空间,要么选错类型导致查询时无法走索引、类型转换消耗额外资源。合理的数据类型选择需要同时兼顾存储空间和性能两个维度,不能只偏向其中一方。

数据类型选择的核心原则
选择数据类型时首先要遵循几个基础原则,这些原则是所有选型决策的前提:
- 更小的通常更好:在满足存储需求的前提下,优先选择占用存储空间更小的数据类型,更小的类型通常处理速度更快,占用的内存和磁盘空间更少。
- 简单就好:能用简单类型就不用复杂类型,比如存储日期优先用<date>或<datetime>,而不是用字符串存储日期格式,简单类型的比较和操作效率更高。
- 尽量避免NULL:除非字段确实允许为空,否则尽量设置为NOT NULL,可为NULL的列会让索引、统计和值比较变得更复杂,还会额外占用存储空间。
常用数据类型的选型建议
整数类型
mysql的整数类型包括TINYINT、SMALLINT、MEDIUMINT、INT、BIGINT,分别对应1、2、3、4、8字节的存储空间,存储范围依次扩大。选择时要根据字段的实际取值范围确定:
- 存储用户年龄、状态标识这类小范围数值,优先用TINYINT,比如状态字段只有0-5几个取值,用TINYINT足够,不需要用INT。
- 存储订单ID、用户ID这类可能需要自增的标识,要根据预估的数据量选择,比如预估数据量不超过20亿,用INT即可,超过再考虑BIGINT。
整数类型还可以指定UNSIGNED属性,表示不允许负数,可将正数的存储上限提升一倍,比如TINYINT UNSIGNED的存储范围是0-255,而普通TINYINT是-128到127,适合存储不会为负数的场景。
字符串类型
字符串类型常用的有CHAR和VARCHAR,两者的存储方式差异很大,选型时要结合字段特点判断:
| 类型 | 特点 | 适用场景 |
|---|---|---|
| CHAR | 定长存储,不足长度会用空格填充,检索时去掉尾部空格,存储长度固定,处理速度快 | 存储长度固定的内容,比如手机号、身份证号、MD5值,长度不会变化 |
| VARCHAR | 变长存储,只占用实际需要的空间,额外需要1-2字节存储长度,更新时可能产生碎片 | 存储长度不固定的内容,比如用户昵称、地址、商品描述,长度波动较大 |
需要注意VARCHAR的长度设置要合理,不要盲目设置很大的长度,比如用户昵称最多20个字符,就设置VARCHAR(20),而不是VARCHAR(255),过长的定义会影响内存临时表的处理效率。
日期和时间类型
存储日期时间时,不要使用字符串类型,优先选择mysql原生的日期时间类型:
- 只需要存储日期,用<date>类型,占用3字节,格式为YYYY-MM-DD。
- 需要存储日期和时间,用<datetime>类型,占用8字节,范围从1000-01-01到9999-12-31,和时区无关。
- 如果需要存储当前时间戳,或者需要和时区关联,用<timestamp>类型,占用4字节,范围从1970-01-01到2038-01-19,会随时区变化。
性能与存储空间平衡的示例
下面通过一个用户表的建表示例,展示如何合理选择数据类型:
-- 合理的用户表建表语句 CREATE TABLE `user` ( `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '用户ID', `phone` CHAR(11) NOT NULL COMMENT '手机号', `nickname` VARCHAR(20) NOT NULL COMMENT '用户昵称', `age` TINYINT UNSIGNED NOT NULL COMMENT '用户年龄', `status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态 0禁用 1正常', `register_time` DATETIME NOT NULL COMMENT '注册时间', `last_login_time` TIMESTAMP NULL DEFAULT NULL COMMENT '最后登录时间', PRIMARY KEY (`id`), KEY `idx_phone` (`phone`), KEY `idx_status` (`status`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表';
这个建表语句中,id用INT UNSIGNED满足大部分场景的用户量需求,phone用CHAR(11)匹配手机号固定长度的特点,nickname用VARCHAR(20)适配昵称长度波动,age和status用TINYINT减少存储开销,register_time用DATETIME存储固定日期时间,last_login_time用TIMESTAMP方便关联时区,整体既控制了存储空间,也保障了查询时的索引效率。
常见选型误区
实际开发中常见的错误选型包括:
- 所有整数都用INT,不管取值范围,导致小字段浪费存储空间。
- 用VARCHAR存储固定长度的内容,比如MD5值、手机号,不如CHAR处理效率高。
- 用字符串存储日期时间,查询时无法走日期范围索引,还会产生类型转换开销。
- VARCHAR长度设置过大,比如所有文本字段都设置VARCHAR(255),影响临时表处理性能。
只要在建表时多结合字段的实际使用场景思考,遵循更小的、更简单的、尽量避免NULL的原则,就能选到合适的数据类型,实现存储空间和性能的平衡。