Appearance
MySQL 数据类型详解
表设计看起来像是在“选字段类型”,但真正落到工程里,它其实在同时影响好几件事:
- 一行数据能存什么
- 一行数据会占多少存储空间
- 索引会变多大
- 查询和更新会有多少额外成本
- 字段语义是否清晰
很多线上问题,最后追溯到根源,往往并不是 SQL 写错了,而是字段类型一开始就选得不够合适。
这篇文章把 MySQL 常见数据类型按类别整理出来,并尽量把下面几个方面讲清楚:
- 它们分别适合存什么
- 各自有什么特点
- 大概占多少存储空间
- 能存多大的范围
- 实际建模时该怎么选
1. 先从大类上看:MySQL 常见数据类型有哪些
可以粗分成 6 类:
- 数值类型
- 字符串类型
- 日期时间类型
- 枚举集合类型
- 二进制类型
- JSON 类型
如果先只记一个总览,可以记成下面这张表:
| 类型大类 | 常见类型 | 主要用途 |
|---|---|---|
| 数值类型 | tinyint、int、bigint、decimal、float、double | 数量、金额、分值、状态、ID |
| 字符串类型 | char、varchar、text | 名称、标题、邮箱、正文 |
| 日期时间类型 | date、time、datetime、timestamp、year | 日期、时间、创建时间、更新时间 |
| 枚举集合类型 | enum、set | 固定可选值、小范围标识 |
| 二进制类型 | bit、binary、varbinary、blob | 二进制标记、文件片段、原始字节内容 |
| JSON 类型 | json | 结构相对灵活的半结构化数据 |
2. 整数类型
整数类型是业务表里最常见的一类类型,常用于:
- 主键
- 状态值
- 数量
- 计数器
- 时间戳
2.1 整数类型对比表
| 类型 | 存储大小 | 有符号范围 | 无符号范围 | 常见场景 |
|---|---|---|---|---|
tinyint | 1 字节 | -128 ~ 127 | 0 ~ 255 | 状态位、布尔标记、小范围枚举 |
smallint | 2 字节 | -32768 ~ 32767 | 0 ~ 65535 | 较小范围计数、业务编号 |
mediumint | 3 字节 | -8388608 ~ 8388607 | 0 ~ 16777215 | 中等范围计数,实际业务中相对少见 |
int | 4 字节 | -2147483648 ~ 2147483647 | 0 ~ 4294967295 | 最常见的整数类型 |
bigint | 8 字节 | -2^63 ~ 2^63-1 | 0 ~ 2^64-1 | 主键、大 ID、大计数、毫秒时间戳 |
2.2 整数类型怎么选
可以记这个顺序:
- 状态值、布尔开关,优先考虑
tinyint - 普通数量、页码、年龄、计数,通常
int就够了 - 主键、雪花 ID、超大计数,优先考虑
bigint
2.3 注意点
- 不要为了“保险”所有整数都上
bigint - 字段越大,行记录和索引也会跟着变大
- 能明确范围时,尽量选刚好够用的类型
2.4 boolean 是什么
MySQL 里的 boolean / bool 本质上通常只是 tinyint(1) 的别名。
所以:
0通常表示假1通常表示真
它不是某种独立的底层布尔存储类型。
3. 定点数与浮点数
涉及金额、比例、分值时,最容易出错的不是语法,而是类型选择。
3.1 对比表
| 类型 | 存储大小 | 取值特点 | 精度特点 | 常见场景 |
|---|---|---|---|---|
decimal(M,D) | 变长,和精度相关 | 十进制定点数 | 精确 | 金额、税率、对账数据 |
float | 4 字节 | 浮点数 | 约 7 位有效数字 | 对精度要求不高的小数 |
double | 8 字节 | 浮点数 | 约 15~16 位有效数字 | 一般科学计算、统计计算 |
3.2 decimal
decimal(M,D) 的含义通常是:
M表示总位数D表示小数位数
例如:
sql
price decimal(10, 2)表示:
- 总共最多 10 位
- 其中 2 位是小数
- 剩下 8 位是整数部分
它的最大优势是:十进制精确。
所以金额类字段通常优先考虑 decimal。
3.3 float 和 double
它们的特点是:
- 存储空间固定
- 计算速度通常不错
- 但存在精度误差
所以更适合:
- 对精度没那么敏感的统计值
- 科学计算
- 近似值场景
3.4 怎么选
| 场景 | 更推荐的类型 | 原因 |
|---|---|---|
| 金额、汇率、优惠、税费 | decimal | 精度要求高 |
| 近似统计、测量值 | float / double | 可接受近似误差 |
| 默认小数业务字段 | decimal | 更稳妥 |
4. 字符串类型
字符串类型最容易被滥用,也最容易造成行过宽、索引过大、查询变慢。
4.1 常见字符串类型对比表
| 类型 | 存储方式 | 可存内容 | 空间特点 | 常见场景 |
|---|---|---|---|---|
char(n) | 定长 | 最多 n 个字符 | 长度稳定,短内容也按接近固定长度处理 | 国家码、固定状态码 |
varchar(n) | 变长 | 最多 n 个字符 | 更接近“存多少用多少” | 用户名、标题、邮箱、手机号 |
tinytext | 长文本 | 约 255B | 适合比短字符串更长的文本 | 极短备注 |
text | 长文本 | 约 64KB | 面向较长文本 | 正文、评论、备注 |
mediumtext | 长文本 | 约 16MB | 更长内容 | 长文章、大段富文本 |
longtext | 长文本 | 约 4GB | 超长文本 | 极大文本,不宜滥用 |
4.2 char 和 varchar
最核心的区别是:
char更偏固定长度varchar更偏可变长度
在业务里大多数字符串字段,默认通常更偏向 varchar,因为大部分字符串长度都不稳定。
4.3 真正影响空间的是什么
这里要特别注意:
- 字段定义里写的是“字符数”
- 真正落到存储上时,还要乘上字符集带来的字节消耗
例如在 utf8mb4 下:
- 一个字符最多可能占 4 字节
- 所以
varchar(100)不等于只占 100 字节
4.4 怎么选
| 场景 | 更推荐的类型 | 原因 |
|---|---|---|
| 固定长度短字段 | char | 语义明确,长度稳定 |
| 大多数业务字符串字段 | varchar | 更灵活,通常更节省空间 |
| 文章正文、长备注、富文本 | text 及更大文本类型 | 明显超出普通短字符串范围 |
5. 日期和时间类型
时间类型的选择,影响的不只是展示格式,还包括:
- 范围是否够用
- 是否带时区语义
- 排序与索引是否自然
5.1 日期时间类型对比表
| 类型 | 存储大小 | 可存范围 | 特点 | 常见场景 |
|---|---|---|---|---|
date | 3 字节 | 1000-01-01 ~ 9999-12-31 | 只存日期 | 生日、账期日期 |
time | 3 字节 | -838:59:59 ~ 838:59:59 | 只存时间 / 时长 | 工时、耗时、时间段 |
datetime | 5 字节(不含小数秒) | 1000-01-01 00:00:00 ~ 9999-12-31 23:59:59 | 日期时间都存,范围大 | 创建时间、业务时间 |
timestamp | 4 字节(不含小数秒) | 1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC | 更适合时间戳语义,范围较小 | 更新时间、系统审计时间 |
year | 1 字节 | 1901 ~ 2155(以及 0000) | 只存年份 | 年份维度字段 |
说明:
- 如果开启小数秒精度,
time、datetime、timestamp还会额外增加存储字节 - 大多数业务表里最常用的是
datetime和timestamp
5.2 datetime 和 timestamp 怎么选
| 维度 | datetime | timestamp |
|---|---|---|
| 范围 | 更大 | 更小,受 2038 问题影响 |
| 存储大小 | 通常更大一点 | 通常更小一点 |
| 语义 | 更像“业务时间” | 更像“系统记录时间” |
更常见的经验是:
- 业务时间、预约时间、活动开始结束时间,更常用
datetime - 系统更新时间、记录变更时间,也常见
timestamp
如果你不想被范围问题卡住,很多业务场景直接统一用 datetime 也很常见。
6. 枚举和集合类型
这类类型不是最常用,但偶尔会出现。
6.1 对比表
| 类型 | 特点 | 存储大小 | 常见场景 |
|---|---|---|---|
enum | 单选值,值来自固定列表 | 通常 1~2 字节 | 性别、有限状态值 |
set | 多选值,可从固定集合中选多个 | 和成员数量相关,通常按位存储 | 权限标记、小范围标签 |
6.2 怎么理解
enum 更像:从固定列表里选一个。
而 set 更像:从固定列表里选多个。
6.3 使用建议
工程上通常会更谨慎地使用它们,因为:
- 业务枚举经常变化
- 后续扩展和迁移不一定方便
- 很多团队更愿意把状态设计成
tinyint+ 应用层枚举
7. 二进制类型
如果要存原始字节,而不是普通字符文本,就会用到这类类型。
7.1 对比表
| 类型 | 特点 | 典型容量 | 常见场景 |
|---|---|---|---|
bit(m) | 位字段 | 最多 64 位 | 位标志、权限位 |
binary(n) | 定长二进制 | 最多 n 字节 | 固定长度字节串 |
varbinary(n) | 变长二进制 | 最多 n 字节 | 可变长度原始字节 |
tinyblob | 二进制大对象 | 约 255B | 小块二进制内容 |
blob | 二进制大对象 | 约 64KB | 文件片段、二进制缓存 |
mediumblob | 二进制大对象 | 约 16MB | 较大二进制内容 |
longblob | 二进制大对象 | 约 4GB | 超大二进制内容 |
7.2 使用建议
虽然 MySQL 能存二进制大对象,但真实系统里通常会谨慎:
- 小对象还能接受
- 大文件往往更适合对象存储或文件系统
- 数据库里只存元数据和访问地址更常见
8. JSON 类型
8.1 它是什么
MySQL 的 json 类型适合存半结构化数据。
例如:
- 扩展配置
- 动态属性
- 结构不完全固定的附加信息
8.2 特点
- 内容结构比普通字符串更明确
- 适合灵活字段
- 不适合把一切都塞进去当万能字段
8.3 使用场景
常见场景:
- 商品扩展属性
- 页面配置
- 审计上下文
8.4 注意点
json不等于不要建模- 高频过滤条件如果都藏在
json里,查询和索引设计会变麻烦 - 结构稳定的核心字段,仍然优先拆成普通列
9. 一张更实用的选型总表
| 字段场景 | 更推荐的类型 | 理由 |
|---|---|---|
| 状态、布尔值、小范围枚举 | tinyint | 轻量、清晰、常见 |
| 普通数量、计数 | int | 足够常用且平衡 |
| 主键、大 ID、大计数 | bigint | 范围更大 |
| 金额 | decimal | 精度可靠 |
| 普通短字符串 | varchar | 更灵活 |
| 固定长度短标识 | char | 语义明确 |
| 长文本正文 | text / mediumtext | 适合长内容 |
| 业务时间 | datetime | 范围大、表达自然 |
| 系统更新时间 | timestamp / datetime | 常见审计字段 |
| 灵活扩展属性 | json | 适合半结构化数据 |
10. 几个容易踩坑的点
10.1 不要默认所有数字都用 bigint
字段越大,行和索引就越大,缓存命中率和整体成本都会受影响。
10.2 金额不要用 float 或 double
金额最怕精度误差,默认优先考虑 decimal。
10.3 大文本不要随手塞进高频核心表
列表页高频读取字段和低频大文本字段,往往更适合拆开。
10.4 varchar(255) 不是万能默认值
很多人为了省事,字符串字段一律 varchar(255)。这虽然常见,但并不总是合理。
更好的思路是:
- 看业务上大概能到多长
- 给出有依据的长度上限
- 避免无意义放大
10.5 选类型不只是看“能不能存下”
真正要同时看的是:
- 语义是否准确
- 索引成本高不高
- 查询会不会频繁使用
- 后续扩展是否方便
11. 总结
如果把 MySQL 数据类型压缩成最核心的选型原则,可以记下面几句:
- 能用更小的整数,就不要无意义放大
- 金额优先
decimal - 大多数字符串字段优先
varchar - 固定长度短字段再考虑
char - 长文本和高频核心字段尽量分开
- 业务时间优先想清楚用
datetime还是timestamp json适合扩展字段,不适合替代正常建模
真正好的字段设计,不是把类型表硬记下来,而是看到一个业务字段时,能立刻判断:
它需要多大范围、多少精度、多少空间,以及未来会怎么被查询和索引。