now()返回语句开始执行的固定时间戳,主从同步时binlog记录该常量值,确保一致;sysdate()每次调用实时获取系统时间,主从执行时刻不同导致时间错乱、索引失效。

NOW() 不会导致主从同步延迟;真正影响主从一致性的,是误用 SYSDATE()。 主库写入时若用了 SYSDATE(),从库重放该语句会得到不同时间值,从而破坏数据逻辑一致性——这不是“延迟”,而是“错乱”。
为什么 NOW() 在主从环境下更安全
NOW() 的值在语句解析阶段就已确定,并作为常量写入 binlog。从库回放时直接复用该固定时间戳,不重新调用系统时钟。
- 主库执行
INSERT INTO log (ts) VALUES (NOW())→ binlog 记录为INSERT INTO log (ts) VALUES ('2026-05-07 00:08:12') - 从库读取 binlog 后照搬执行,时间值完全一致
- 即使主从服务器系统时间相差几分钟,也不影响该字段取值
SYSDATE() 为什么会在主从上产生不同结果
SYSDATE() 每次调用都触发操作系统级时间获取(如 gettimeofday()),它不缓存、不快照,只返回函数执行瞬间的实时时间。
- 主库执行
INSERT INTO log (ts) VALUES (SYSDATE())→ binlog 记录的是语句本身,不是具体时间值 - 从库回放时再次执行
SYSDATE(),此时系统时间可能已偏移(网络延迟、IO 延迟、负载差异都会放大偏差) - 主库插入
'2026-05-07 00:08:12',从库却插入'2026-05-07 00:08:15',主从 ts 字段不再相等
为什么 SYSDATE() 还会让索引失效
优化器无法预估 SYSDATE() 的返回值,因此无法将含 SYSDATE() 的表达式(如 created_at > SYSDATE() - INTERVAL 1 HOUR)转换为确定的范围条件。
-
NOW() - INTERVAL 1 HOUR是常量表达式,优化器可提前计算出边界值,走索引 -
SYSDATE() - INTERVAL 1 HOUR被视为非确定性函数,MySQL 默认拒绝用其做索引范围估算 - 常见现象:执行计划中
type显示ALL,key为NULL,哪怕created_at上有索引
哪些场景下真的需要 SYSDATE()
极少。只有当业务明确要求“每行记录必须精确反映该行实际写入操作发生的物理时刻”,且能接受主从时间不一致、索引不可用、事务内时间跳跃等代价时才考虑。
- 审计日志中需记录 SQL 实际执行到某条语句的毫秒级时间点(例如配合
SLEEP()做分步打点) - 调试存储过程内部耗时,用
SELECT SYSDATE(), ..., SYSDATE()观察各步骤真实间隔 - 注意:
CURRENT_TIMESTAMP列默认行为仍基于NOW()语义,不受SYSDATE()影响
最易被忽略的一点:NOW() 的“不变性”只作用于单条语句或事务内;跨语句、跨连接之间,它仍是变化的——别把它当成全局时钟。而 SYSDATE() 的“变”是不可控的,不仅跨语句变,同一语句里多次调用也可能不同,这才是它危险的根源。











