Skip to content

MySQL 数据类型详解

表设计看起来像是在“选字段类型”,但真正落到工程里,它其实在同时影响好几件事:

  1. 一行数据能存什么
  2. 一行数据会占多少存储空间
  3. 索引会变多大
  4. 查询和更新会有多少额外成本
  5. 字段语义是否清晰

很多线上问题,最后追溯到根源,往往并不是 SQL 写错了,而是字段类型一开始就选得不够合适。

这篇文章把 MySQL 常见数据类型按类别整理出来,并尽量把下面几个方面讲清楚:

  1. 它们分别适合存什么
  2. 各自有什么特点
  3. 大概占多少存储空间
  4. 能存多大的范围
  5. 实际建模时该怎么选

1. 先从大类上看:MySQL 常见数据类型有哪些

可以粗分成 6 类:

  1. 数值类型
  2. 字符串类型
  3. 日期时间类型
  4. 枚举集合类型
  5. 二进制类型
  6. JSON 类型

如果先只记一个总览,可以记成下面这张表:

类型大类常见类型主要用途
数值类型tinyintintbigintdecimalfloatdouble数量、金额、分值、状态、ID
字符串类型charvarchartext名称、标题、邮箱、正文
日期时间类型datetimedatetimetimestampyear日期、时间、创建时间、更新时间
枚举集合类型enumset固定可选值、小范围标识
二进制类型bitbinaryvarbinaryblob二进制标记、文件片段、原始字节内容
JSON 类型json结构相对灵活的半结构化数据

2. 整数类型

整数类型是业务表里最常见的一类类型,常用于:

  1. 主键
  2. 状态值
  3. 数量
  4. 计数器
  5. 时间戳

2.1 整数类型对比表

类型存储大小有符号范围无符号范围常见场景
tinyint1 字节-128 ~ 1270 ~ 255状态位、布尔标记、小范围枚举
smallint2 字节-32768 ~ 327670 ~ 65535较小范围计数、业务编号
mediumint3 字节-8388608 ~ 83886070 ~ 16777215中等范围计数,实际业务中相对少见
int4 字节-2147483648 ~ 21474836470 ~ 4294967295最常见的整数类型
bigint8 字节-2^63 ~ 2^63-10 ~ 2^64-1主键、大 ID、大计数、毫秒时间戳

2.2 整数类型怎么选

可以记这个顺序:

  1. 状态值、布尔开关,优先考虑 tinyint
  2. 普通数量、页码、年龄、计数,通常 int 就够了
  3. 主键、雪花 ID、超大计数,优先考虑 bigint

2.3 注意点

  1. 不要为了“保险”所有整数都上 bigint
  2. 字段越大,行记录和索引也会跟着变大
  3. 能明确范围时,尽量选刚好够用的类型

2.4 boolean 是什么

MySQL 里的 boolean / bool 本质上通常只是 tinyint(1) 的别名。

所以:

  1. 0 通常表示假
  2. 1 通常表示真

它不是某种独立的底层布尔存储类型。

3. 定点数与浮点数

涉及金额、比例、分值时,最容易出错的不是语法,而是类型选择。

3.1 对比表

类型存储大小取值特点精度特点常见场景
decimal(M,D)变长,和精度相关十进制定点数精确金额、税率、对账数据
float4 字节浮点数约 7 位有效数字对精度要求不高的小数
double8 字节浮点数约 15~16 位有效数字一般科学计算、统计计算

3.2 decimal

decimal(M,D) 的含义通常是:

  1. M 表示总位数
  2. D 表示小数位数

例如:

sql
price decimal(10, 2)

表示:

  1. 总共最多 10 位
  2. 其中 2 位是小数
  3. 剩下 8 位是整数部分

它的最大优势是:十进制精确。

所以金额类字段通常优先考虑 decimal

3.3 floatdouble

它们的特点是:

  1. 存储空间固定
  2. 计算速度通常不错
  3. 但存在精度误差

所以更适合:

  1. 对精度没那么敏感的统计值
  2. 科学计算
  3. 近似值场景

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 charvarchar

最核心的区别是:

  1. char 更偏固定长度
  2. varchar 更偏可变长度

在业务里大多数字符串字段,默认通常更偏向 varchar,因为大部分字符串长度都不稳定。

4.3 真正影响空间的是什么

这里要特别注意:

  1. 字段定义里写的是“字符数”
  2. 真正落到存储上时,还要乘上字符集带来的字节消耗

例如在 utf8mb4 下:

  1. 一个字符最多可能占 4 字节
  2. 所以 varchar(100) 不等于只占 100 字节

4.4 怎么选

场景更推荐的类型原因
固定长度短字段char语义明确,长度稳定
大多数业务字符串字段varchar更灵活,通常更节省空间
文章正文、长备注、富文本text 及更大文本类型明显超出普通短字符串范围

5. 日期和时间类型

时间类型的选择,影响的不只是展示格式,还包括:

  1. 范围是否够用
  2. 是否带时区语义
  3. 排序与索引是否自然

5.1 日期时间类型对比表

类型存储大小可存范围特点常见场景
date3 字节1000-01-01 ~ 9999-12-31只存日期生日、账期日期
time3 字节-838:59:59 ~ 838:59:59只存时间 / 时长工时、耗时、时间段
datetime5 字节(不含小数秒)1000-01-01 00:00:00 ~ 9999-12-31 23:59:59日期时间都存,范围大创建时间、业务时间
timestamp4 字节(不含小数秒)1970-01-01 00:00:01 UTC ~ 2038-01-19 03:14:07 UTC更适合时间戳语义,范围较小更新时间、系统审计时间
year1 字节1901 ~ 2155(以及 0000只存年份年份维度字段

说明:

  1. 如果开启小数秒精度,timedatetimetimestamp 还会额外增加存储字节
  2. 大多数业务表里最常用的是 datetimetimestamp

5.2 datetimetimestamp 怎么选

维度datetimetimestamp
范围更大更小,受 2038 问题影响
存储大小通常更大一点通常更小一点
语义更像“业务时间”更像“系统记录时间”

更常见的经验是:

  1. 业务时间、预约时间、活动开始结束时间,更常用 datetime
  2. 系统更新时间、记录变更时间,也常见 timestamp

如果你不想被范围问题卡住,很多业务场景直接统一用 datetime 也很常见。

6. 枚举和集合类型

这类类型不是最常用,但偶尔会出现。

6.1 对比表

类型特点存储大小常见场景
enum单选值,值来自固定列表通常 1~2 字节性别、有限状态值
set多选值,可从固定集合中选多个和成员数量相关,通常按位存储权限标记、小范围标签

6.2 怎么理解

enum 更像:从固定列表里选一个。

set 更像:从固定列表里选多个。

6.3 使用建议

工程上通常会更谨慎地使用它们,因为:

  1. 业务枚举经常变化
  2. 后续扩展和迁移不一定方便
  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 能存二进制大对象,但真实系统里通常会谨慎:

  1. 小对象还能接受
  2. 大文件往往更适合对象存储或文件系统
  3. 数据库里只存元数据和访问地址更常见

8. JSON 类型

8.1 它是什么

MySQL 的 json 类型适合存半结构化数据。

例如:

  1. 扩展配置
  2. 动态属性
  3. 结构不完全固定的附加信息

8.2 特点

  1. 内容结构比普通字符串更明确
  2. 适合灵活字段
  3. 不适合把一切都塞进去当万能字段

8.3 使用场景

常见场景:

  1. 商品扩展属性
  2. 页面配置
  3. 审计上下文

8.4 注意点

  1. json 不等于不要建模
  2. 高频过滤条件如果都藏在 json 里,查询和索引设计会变麻烦
  3. 结构稳定的核心字段,仍然优先拆成普通列

9. 一张更实用的选型总表

字段场景更推荐的类型理由
状态、布尔值、小范围枚举tinyint轻量、清晰、常见
普通数量、计数int足够常用且平衡
主键、大 ID、大计数bigint范围更大
金额decimal精度可靠
普通短字符串varchar更灵活
固定长度短标识char语义明确
长文本正文text / mediumtext适合长内容
业务时间datetime范围大、表达自然
系统更新时间timestamp / datetime常见审计字段
灵活扩展属性json适合半结构化数据

10. 几个容易踩坑的点

10.1 不要默认所有数字都用 bigint

字段越大,行和索引就越大,缓存命中率和整体成本都会受影响。

10.2 金额不要用 floatdouble

金额最怕精度误差,默认优先考虑 decimal

10.3 大文本不要随手塞进高频核心表

列表页高频读取字段和低频大文本字段,往往更适合拆开。

10.4 varchar(255) 不是万能默认值

很多人为了省事,字符串字段一律 varchar(255)。这虽然常见,但并不总是合理。

更好的思路是:

  1. 看业务上大概能到多长
  2. 给出有依据的长度上限
  3. 避免无意义放大

10.5 选类型不只是看“能不能存下”

真正要同时看的是:

  1. 语义是否准确
  2. 索引成本高不高
  3. 查询会不会频繁使用
  4. 后续扩展是否方便

11. 总结

如果把 MySQL 数据类型压缩成最核心的选型原则,可以记下面几句:

  1. 能用更小的整数,就不要无意义放大
  2. 金额优先 decimal
  3. 大多数字符串字段优先 varchar
  4. 固定长度短字段再考虑 char
  5. 长文本和高频核心字段尽量分开
  6. 业务时间优先想清楚用 datetime 还是 timestamp
  7. json 适合扩展字段,不适合替代正常建模

真正好的字段设计,不是把类型表硬记下来,而是看到一个业务字段时,能立刻判断:

它需要多大范围、多少精度、多少空间,以及未来会怎么被查询和索引。

基于 VitePress 构建的个人技术笔记。