整型 TINYINT 到 BIGINT 的存储差异与选择策略

整型 TINYINT 到 BIGINT 的存储差异与选择策略

MySQL 整型类型一览

MySQL 提供了 5 种整型,区别在于存储空间和取值范围:

类型 字节数 有符号范围 无符号范围
TINYINT 1 -128 ~ 127 0 ~ 255
SMALLINT 2 -32,768 ~ 32,767 0 ~ 65,535
MEDIUMINT 3 -8,388,608 ~ 8,388,607 0 ~ 16,777,215
INT 4 -2,147,483,648 ~ 2,147,483,647 0 ~ 4,294,967,295
BIGINT 8 -2^63 ~ 2^63-1 0 ~ 2^64-1

核心差异解析

1. 存储空间差异

  • TINYINT (1字节):节省空间的效果最明显。如果有 1000 万行数据,TINYINT 比 INT 省 30MB,比 BIGINT 省 70MB
  • INT (4字节):最通用的选择。绝大多数场景够用
  • BIGINT (8字节):空间翻倍。除非必要(自增主键预估超过 42 亿),不建议滥用

一个典型误区:用户状态字段(0/1/2)用 INT,完全可以改用 TINYINT。

2. 显示宽度(ZEROFILL)

MySQL 允许指定 INT(11) 这样的显示宽度,但这不影响存储空间和取值范围。显示宽度仅在使用 ZEROFILL 时有效,用于补零显示。从 MySQL 8.0.17 起,显示宽度已被废弃,不再建议使用。

3. 有符号 vs 无符号

MySQL 对整个列的声明决定有符号或无符号:

age TINYINT UNSIGNED  -- 0~255,适合年龄
status TINYINT        -- -128~127,默认有符号

如果业务上值不会为负数,加上 UNSIGNED 可以扩展上限一倍。但要注意:MySQL 中两个 UNSIGNED 整数相减结果还是 UNSIGNED,可能导致意外的环绕行为。

4. 自增主键的选择

这是整型选择最常见的面试题:

  • INT UNSIGNED:最大 42.9 亿,一般业务足够
  • BIGINT UNSIGNED:几乎用不完,适合高并发或超大量数据业务
  • 如果使用分布式 ID(雪花算法等),ID 超过 INT 上限,必须用 BIGINT

一个常见的生产事故:某表自增主键用 INT 达到上限,INSERT 报 Duplicate entryOut of range 错误,导致业务中断。因此,对可能增长到亿级的表,建议直接使用 BIGINT。

5. 布尔值的表示

MySQL 没有真正的布尔类型。BOOLBOOLEAN 只是 TINYINT(1) 的别名:
– 0 = false
– 非 0 = true(通常用 1)

相比之下,如果用 BIT(1) 存储布尔值,虽然更语义化,但 BIT 类型在查询优化上不如 TINYINT 友好(不能走索引、比较时类型转换多)。

6. 性能差异

在 CPU 层面,操作不同宽度的整数对现代处理器来说差异极小。主要性能差异来自:
内存占用:BIGINT 占缓冲池更多空间,减少缓存行数
IO 带宽:更大的类型意味着更大的行记录,每次 IO 能读的行数减少
索引大小:主键为 BIGINT 时,二级索引也隐式包含主键,导致二级索引变大

选择策略

场景 推荐类型 理由
状态/标志/性别 TINYINT 值范围小,节省空间
年龄/评分/小分类 TINYINT UNSIGNED 正数范围够用
中量级枚举(<32000) SMALLINT 比 INT 省一半空间
普通 ID / 计数器 INT UNSIGNED 平衡空间和取值
预计超 42 亿的主键 BIGINT 防溢出
分布式 ID BIGINT 雪花算法等生成值超 INT 范围
金额(分) INT 或 BIGINT 如果金额大需 BIGINT

面试常见追问

Q:为什么不用 VARCHAR 存数字?
A:数字类型比字符串排序更高效(二进制比较 vs 字典序),占用空间更小,且保证计算正确性(’2′ > ’10’ 的问题)。

Q:INT(10) 和 INT(1) 有区别吗?
A:没有。存储空间和取值范围相同,显示宽度仅配合 ZEROFILL 使用,8.0.17+ 已废弃。

Q:自增主键用 BIGINT 有什么缺点?
A:占 8 字节(INT 的两倍),导致聚簇索引更大、二级索引更大、缓冲池缓存行数减少。但对多数场景来说,避免溢出的收益远大于这额外空间成本。

© 版权声明
THE END
喜欢就支持一下吧
点赞10 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容