mysql 5.6.4 是 datetime 存储结构分水岭:此前固定 8 字节,此后基础压缩为 5 字节(年月日时分秒打包),小数秒额外增加 0–3 字节;timestamp 始终为 4 字节 unix 时间戳整数,范围受限于 2038 年。

MySQL 5.6.4 是 datetime 存储结构变化的分水岭
MySQL 在 5.6.4 版本对 DATETIME 做了底层存储优化,直接导致它和 TIMESTAMP 的字节占用逻辑彻底分道扬镳。
- 5.6.4 之前:
DATETIME固定占 8 字节(YYYYMMDDHHMMSS 全字段按整数打包);TIMESTAMP固定占 4 字节(本质是带符号 32 位整数,存 UTC 秒数) - 5.6.4 及之后:
DATETIME基础部分压缩为 5 字节(年月日时分秒打包为一个整数),小数秒(DATETIME(3)、DATETIME(6))额外加 0–3 字节;TIMESTAMP仍稳定在 4 字节,没变 - 这意味着:不带小数位的
DATETIME(如DATETIME或DATETIME(0))实际只用 5 字节,比旧版省 3 字节,但依然比TIMESTAMP多 1 字节
TIMESTAMP 的 4 字节本质是 Unix 时间戳整数
TIMESTAMP 的存储结构从一开始就是“时间点”的抽象——它不存格式化字符串,而是存自 1970-01-01 00:00:00 UTC 起的秒数(或微秒数,取决于精度),所以天然适合用 32 位有符号整数表示。
- 这就是为什么它的范围被死死卡在
1970-01-01 00:00:01到2038-01-19 03:14:07:32 位整数最大值是 2147483647 秒 - 它必须做时区转换:插入时把会话时区时间转成 UTC 整数存;查询时再把该整数转回当前会话时区的可读时间
- 这种设计让
TIMESTAMP非常轻量,但代价是丧失时区无关性和长期可用性
DATETIME 的 5 字节是“紧凑字符串”的二进制编码
DATETIME 的新存储方式不是简单压缩,而是把 YYYYMMDDHHMMSS 六个字段打包成一个整数:年占 12 位、月 4 位、日 5 位、时 5 位、分 6 位、秒 6 位,合计刚好 43 位 → 实际用 5 字节(40 位)能覆盖,高位补零即可。
- 这个整数不代表“距纪元秒数”,只是对时间字面量的高效打包,所以不依赖时区,也不受 2038 年限制
- 小数秒单独存:
DATETIME(3)加 3 字节(毫秒),DATETIME(6)加 3 字节(微秒),但基础 5 字节不变 - 因此
DATETIME的“省空间”是有条件的:必须确认业务不需要毫秒精度,且 MySQL ≥ 5.6.4
别拿 4 字节 vs 5 字节做选型决策
单看存储差异容易误判。真正影响线上系统的是行为差异,不是那 1 字节:
-
TIMESTAMP的 4 字节换来的是:单表最多一个字段能设CURRENT_TIMESTAMP默认值;跨时区查数据结果会漂移;2038 年后写入直接报错Incorrect datetime value -
DATETIME多出的 1 字节换来了:任意字段都能配DEFAULT CURRENT_TIMESTAMP(5.6.5+);存什么时间就是什么时间;支持千年尺度的历史/未来时间 - 对千万级大表,每行省 1 字节 ≈ 总共省几十 MB;而一次时区转换错误或 2038 年故障,排查成本远超磁盘预算
底层存储不同,是因为设计目标根本不同:TIMESTAMP 是“全球统一时间点”的轻量表达,DATETIME 是“本地墙上时间”的可靠快照。选哪个,先想清楚你存的到底是什么。











