DATETIME 与 TIMESTAMP 的选择

DATETIME 与 TIMESTAMP 的选择

基本区别

特性 DATETIME TIMESTAMP
存储空间 5 字节(8.0)+ 小数秒 4 字节 + 小数秒
取值范围 1000-01-01 ~ 9999-12-31 1970-01-01 00:00:01 ~ 2038-01-19 03:14:07
时区处理 不处理,存什么取什么 存储时转为 UTC,查询时转回会话时区
自动初始化 需手动指定 DEFAULT 支持 DEFAULT CURRENT_TIMESTAMP
自动更新 需手动指定 ON UPDATE 支持 ON UPDATE CURRENT_TIMESTAMP

最重要的问题:2038 年问题

TIMESTAMP 使用 4 字节存储,以秒为单位从 1970-01-01 00:00:00 UTC 开始计数,最大值为 2038-01-19 03:14:07 UTC。

这是一个真实的 Y2K 级别的兼容性问题。存储超过该时间的时间戳时,TIMESTAMP 会溢出。

DATETIME 没有这个限制,它的范围到公元 9999 年。

时区处理差异

这是两者最核心的行为区别:

-- 假设会话时区为 '+08:00'(北京时间)
INSERT INTO t VALUES ('2025-06-15 10:00:00');

-- DATETIME 列:直接存储 2025-06-15 10:00:00
-- TIMESTAMP 列:转为 UTC 存储 → 2025-06-15 02:00:00(-8小时)

-- 切换会话时区
SET time_zone = '+00:00';

-- DATETIME 列:显示 2025-06-15 10:00:00(不变,因为是插入时的字面值)
-- TIMESTAMP 列:显示 2025-06-15 02:00:00(转为 UTC 显示)

这意味着:
TIMESTAMP 适合”记录一个绝对时刻”(如订单创建时间)
DATETIME 适合”记录一个日历时间”(如生日、会议开始时间——不应受时区改变)

存储空间和性能

从 MySQL 5.6.4 开始,DATETIME 的存储从 8 字节改为 5 字节(不含小数秒),与 TIMESTAMP 的差距缩小了:

  • TIMESTAMP:4 字节(精确到秒)
  • DATETIME:5 字节(精确到秒)
  • 带小数秒(如 3 位毫秒精度):各加 1 字节

性能上两者差异极小。TIMESTAMP 因为有时区转换需要额外 CPU,但现代 MySQL 下基本可忽略。真正的性能差异来自:
索引大小:TIMESTAMP 更小,索引页能缓存更多行
分区表:部分场景下 TIMESTAMP 做分区键更方便

自动初始化与自动更新

CREATE TABLE events (
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

DATETIME 从 MySQL 5.6.5 起也支持 DEFAULT 和 ON UPDATE,语法相同:

CREATE TABLE events (
    created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

所以”TIMESTAMP 才能自动设当前时间”已经是旧观念了。

小数秒精度

两者都支持 fractional seconds(小数秒),精度可达微秒:

CREATE TABLE t (
    a TIMESTAMP(3),    -- 毫秒级精度
    b DATETIME(6),     -- 微秒级精度
    c TIMESTAMP(0)     -- 精确到秒(默认)
);

选择策略

优先使用 DATETIME 的场景

  1. 未来时间:超过 2038 年的日期(如预约系统)
  2. 日历日期:生日、纪念日、固定节假日
  3. 不受时区影响的场景:如”每天 8 点上班”不应受时区变化影响
  4. 跨时区应用:当需要”记住用户输入的原始时间”时

优先使用 TIMESTAMP 的场景

  1. 事件时间戳:日志时间、创建时间、更新时间(绝对时刻)
  2. 全球应用:自动处理时区转换,用户看到自己时区的时间
  3. 空间敏感:需要节省几字节的场景
  4. 时间范围在 1970-2038 内:大部分在线业务场景

安全选择:BIGINT 存时间戳

如果两个都纠结,另一种方案是用 BIGINT 存 Unix 时间戳(毫秒或微秒级):
– 无 2038 年问题
– 应用层完全控制时区逻辑
– 排序、比较效率最好
– 但 SQL 中可读性差,调试不便

现代推荐:DATETIME

在 MySQL 8.0 中,DATETIME 和 TIMESTAMP 的功能差距已经基本抹平。考虑到 2038 年问题,默认选择 DATETIME(3) 是更稳妥的实践,存储占用也只有 6 字节(带毫秒)。TIMESTAMP 仅在明确需要自动时区转换且确认时间不会超过 2038 年时使用。

面试常问题

Q:TIMESTAMP 存 ‘2025-06-15 10:00:00’ 在东八区读出来是什么?
A:也是 2025-06-15 10:00:00(前提是会话时区也是东八区)。如果会话切到 UTC,则显示 2025-06-15 02:00:00。

Q:现在 DATETIME 存 5 字节够吗?
A:够。5 字节存到 9999 年,精度到秒。MySQL 8.0 使用紧凑存储。

Q:线上可以从 TIMESTAMP 迁移到 DATETIME 吗?
A:可以,但注意:现有数据以 UTC 存储,迁移时需确保转换正确。建议先 ALTER TABLE 试跑,验证数据一致性。

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

请登录后发表评论

    暂无评论内容