SYSUTCDATETIME() 实际精度仅1–15毫秒,因Windows系统时钟分辨率约15.6ms且SQL Server依赖系统API,不插值;用作列默认值安全,但CTE/视图中多次调用可能被优化器复用。

为什么 SYSUTCDATETIME() 返回的不是你想要的“毫秒级”精度?
直接调用 SYSUTCDATETIME() 看似能拿到高精度 UTC 时间,但实际返回的是 datetime2(7) 类型——理论支持 100 纳秒精度,**SQL Server 底层时钟源和系统调度限制导致真实精度通常只有 1–15 毫秒**。你在同一毫秒内连续执行多次,大概率拿到重复值。
- Windows 系统默认时钟分辨率约 15.6ms(取决于
GetSystemTimeAsFileTime和硬件中断频率) -
SYSUTCDATETIME()不做插值或硬件计时器读取,纯靠系统 API - 在高并发 INSERT 场景下,多个行可能共享同一个
SYSUTCDATETIME()值
如何让 SYSUTCDATETIME() 在 INSERT 中真正“生效”?
它本身是运行时函数,但若写成列默认约束(如 DEFAULT SYSUTCDATETIME()),SQL Server 会在**行插入时刻求值**,这是安全用法;但若在 UPDATE 或子查询中反复引用,要注意表达式重写时机。
- ✅ 推荐:定义列为
created_at DATETIME2(7) DEFAULT SYSUTCDATETIME() - ✅ 安全:显式写入
INSERT INTO t (ts) VALUES (SYSUTCDATETIME()) - ❌ 危险:在 CTE 或视图里多次调用
SYSUTCDATETIME()并期望彼此不同——优化器可能只计算一次 - ⚠️ 注意:
GETUTCDATE()是旧版datetime类型(精度仅 3.33ms),别混用
对比 SYSUTCDATETIME() 和 SYSDATETIMEOFFSET() 的时区行为
两者都返回 datetime2(7),但语义不同:SYSUTCDATETIME() 是纯 UTC 时间值,无时区偏移信息;SYSDATETIMEOFFSET() 返回带本地时区偏移的 datetimeoffset,再转 UTC 需额外计算,容易出错。
- 要存标准 UTC 时间戳(如日志、审计、跨时区比对),必须用
SYSUTCDATETIME() -
SYSDATETIMEOFFSET() AT TIME ZONE 'UTC'会多一次转换开销,且依赖时区名注册表 - 如果字段类型是
datetimeoffset,又想存 UTC,直接用SYSUTCDATETIME() AT TIME ZONE 'UTC'更直白
替代方案:什么时候该放弃 SYSUTCDATETIME()?
当业务要求严格单调递增、或需区分同一毫秒内的操作顺序(比如分布式幂等 ID、事件溯源序列号),单靠 SYSUTCDATETIME() 不够可靠。
- 加辅助列:用
ROWVERSION或IDENTITY+ 时间戳组合判序 - 应用层生成:C# 的
DateTime.UtcNow.Ticks或 Go 的time.Now().UnixNano(),传入 SQL - 慎用
NEWID()或NEWSEQUENTIALID():它们不反映真实时间,仅适合排序 - 注意:SQL Server 2016+ 的
SEQUENCE无法与时间对齐,不能替代时序精度
真实环境里,时间精度瓶颈往往不在函数本身,而在系统时钟同步策略(如是否启用 Windows Time Service 的 NTP 校准)和虚拟机是否启用了高精度定时器(如 Hyper-V 的 Enlightened Timer)。这些细节比选哪个函数更重要。










