NOW() 是语句级时间快照,SYSDATE() 是调用级实时读取,根本区别在于 MySQL 内部绑定时间值的时机:前者在语句解析开始时固化时间,后者每次调用均获取系统当前时间。

NOW() 是语句级时间快照,SYSDATE() 是调用级实时读取
根本区别不在“谁更准”,而在于 MySQL 内部如何绑定时间值:NOW() 在 SQL 语句解析开始时就从内部 TIMESTAMP 变量取值并固化,整条语句里反复调用都返回同一个时间;SYSDATE() 每次执行都直接调用操作系统 gettimeofday() 或类似接口,拿到的是调用那一刻的真实系统时间。
这导致最直观的差异:加 SLEEP() 后,NOW() 两次结果相同,SYSDATE() 两次结果相差约休眠时长。这不是 bug,是设计使然——前者服务于事务一致性,后者服务于实时性。
复制场景下 NOW() 更安全,SYSDATE() 可能主备不一致
在基于 statement 的 binlog 复制模式中,NOW() 的值会被写入 binlog 并在备库重放时复用,保证主备时间一致;而 SYSDATE() 不会记录具体值,备库执行时重新取本地系统时间,若主备服务器时区或系统时间不同,就会产生偏差。
- 如果你用
STATEMENT格式复制,且 SQL 中含SYSDATE(),务必确认主备时区已统一(见下节) -
ROW格式复制不受影响,因为时间值已在变更数据中固化 - 触发器、存储过程内混用两者,可能引发逻辑错乱(比如用
SYSDATE()判断超时,但事务内其他字段用NOW()记录,时间基准不统一)
时区配置不一致会让差异“放大”甚至“错乱”
即使你没用 SLEEP(),NOW() 和 SYSDATE() 也可能显示完全不同时间——这不是函数问题,而是服务端和客户端时区没对齐。
查当前配置:SELECT @@global.time_zone, @@session.time_zone;;查实际偏移:SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP);
- MySQL 服务端启动时读
/etc/timezone或 systemd 配置,但 JDBC 连接默认用 JVM 时区,Pythonpymysql默认用本地系统时区 - Java 应用必须显式指定
serverTimezone=Asia/Shanghai,否则NOW()返回值可能被客户端错误转换 - 推荐统一设为
default-time-zone='+08:00'(而非Asia/Shanghai),避免夏令时切换带来的歧义
索引和优化器对 SYSDATE() 更“谨慎”
SYSDATE() 被标记为非确定性(non-deterministic)函数,MySQL 优化器不会用它做索引下推或常量折叠。例如:WHERE create_time > SYSDATE() - INTERVAL 1 HOUR 无法利用 create_time 索引加速,而 NOW() 可以。
- 不是性能差,而是优化器放弃尝试——因为它无法预判
SYSDATE()的值 - 如果只是用于
INSERT默认值,SYSDATE()和NOW()生成的索引行为完全一致 - 在
WHERE或ORDER BY中频繁使用SYSDATE(),建议先用变量存一次:SET @now = SYSDATE(); SELECT ... WHERE time > @now - INTERVAL 1 HOUR;
真实环境里,NOW() 和 SYSDATE() 的差异往往不是函数本身的问题,而是时区配置、复制模式、索引策略这些“周边”环节没兜住。尤其当看到两个函数返回时间差好几小时,第一反应不该是查文档,而是立刻跑 SELECT TIMEDIFF(NOW(), UTC_TIMESTAMP), TIMEDIFF(SYSDATE(), UTC_TIMESTAMP); 看偏移是否一致。


















