AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • 主页
  • 系统&网络
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • 主页
  • 系统&网络
    • 最新
    • 热门
    • 标签
  • Ubuntu
    • 最新
    • 热门
    • 标签
  • Unix
    • 最新
    • 标签
  • DBA
    • 最新
    • 标签
  • Computer
    • 最新
    • 标签
  • Coding
    • 最新
    • 标签
主页 / dba / 问题 / 175695
Accepted
Riley Major
Riley Major
Asked: 2017-06-08 09:24:01 +0800 CST2017-06-08 09:24:01 +0800 CST 2017-06-08 09:24:01 +0800 CST

为什么 GETUTCDATE 早于 SYSDATETIMEOFFSET?

  • 772

或者,微软是如何让时间旅行成为可能的?

考虑这段代码:

DECLARE @Offset datetimeoffset = sysdatetimeoffset();
DECLARE @UTC datetime = getUTCdate();
DECLARE @UTCFromOffset datetime = CONVERT(datetime,SWITCHOFFSET(@Offset,0));
SELECT
    Offset = @Offset,
    UTC = @UTC,
    UTCFromOffset = @UTCFromOffset,
    TimeTravelPossible = CASE WHEN @UTC < @UTCFromOffset THEN 1 ELSE 0 END;

@Offset设置为before @UTC,但它有时具有较晚的值。(我已经在 SQL Server 2008 R2 和 SQL Server 2016 上尝试过。你必须运行它几次才能发现可疑事件。)

这似乎不仅仅是四舍五入或缺乏精度的问题。(事实上​​,我认为舍入是偶尔“修复”问题的原因。)样本运行的值如下:

  • 抵消
    • 2017-06-07 12:01:58.8801139 -05:00
  • 世界标准时间
    • 2017-06-07 17:01:58.877
  • UTC 从偏移量:
    • 2017-06-07 17:01:58.880

因此日期时间精度允许 .880 作为有效值。

即使是Microsoft 的 GETUTCDATE 示例也显示 SYS* 值晚于旧方法,尽管被更早地选择:

SELECT 'SYSDATETIME()      ', SYSDATETIME();  
SELECT 'SYSDATETIMEOFFSET()', SYSDATETIMEOFFSET();  
SELECT 'SYSUTCDATETIME()   ', SYSUTCDATETIME();  
SELECT 'CURRENT_TIMESTAMP  ', CURRENT_TIMESTAMP;  
SELECT 'GETDATE()          ', GETDATE();  
SELECT 'GETUTCDATE()       ', GETUTCDATE();  
/* Returned:  
SYSDATETIME()            2007-05-03 18:34:11.9351421  
SYSDATETIMEOFFSET()      2007-05-03 18:34:11.9351421 -07:00  
SYSUTCDATETIME()         2007-05-04 01:34:11.9351421  
CURRENT_TIMESTAMP        2007-05-03 18:34:11.933  
GETDATE()                2007-05-03 18:34:11.933  
GETUTCDATE()             2007-05-04 01:34:11.933  
*/

我认为这是因为它们来自不同的底层系统信息。谁能确认并提供详细信息?

微软的 SYSDATETIMEOFFSET 文档说“SQL Server 通过使用 GetSystemTimeAsFileTime() Windows API 获取日期和时间值”(感谢 srutzky),但他们的GETUTCDATE 文档没有那么具体,只说“值来自操作系统运行 SQL Server 实例的计算机”。

(这并不完全是学术性的。我遇到了一个由此引起的小问题。我正在升级一些程序以使用 SYSDATETIMEOFFSET 而不是 GETUTCDATE,希望将来能获得更高的精度,但我开始得到奇怪的排序,因为其他程序是仍在使用 GETUTCDATE 并且偶尔在日志中“跳过”我转换的过程。)

sql-server datetime
  • 1 1 个回答
  • 4038 Views

1 个回答

  • Voted
  1. Best Answer
    Solomon Rutzky
    2017-06-08T13:47:32+08:002017-06-08T13:47:32+08:00

    问题是数据类型粒度/准确性和值来源的组合。

    首先,DATETIME仅准确/精细到每 3 毫秒。因此,从更精确的数据类型转换,例如DATETIMEOFFSET或DATETIME2不只是向上或向下舍入到最接近的毫秒,它可能有 2 毫秒的不同。

    其次,文档似乎暗示了值的来源不同。SYS* 函数使用高精度 FileTime 函数。

    SYSDATETIMEOFFSET文档状态:

    SQL Server 使用 GetSystemTimeAsFileTime() Windows API 获取日期和时间值。

    而GETUTCDATE文档指出:

    此值源自运行 SQL Server 实例的计算机的操作系统。

    然后,在About Time文档中,图表显示了以下两种(几种)类型:

    • System Time = "年、月、日、时、秒和毫秒,取自内部硬件时钟。"
    • 文件时间 = “自 1601 年 1 月 1 日以来的 100 纳秒间隔数。”

    其他线索在StopWatch该类的 .NET 文档中(我的粗斜体强调):

    • 秒表类

      秒表通过计算底层计时器机制中的计时器滴答来测量经过的时间。如果安装的硬件和操作系统支持高分辨率性能计数器,则 Stopwatch 类使用该计数器来测量经过的时间。否则, Stopwatch 类使用系统计时器来测量经过的时间。

    • Stopwatch.IsHighResolution 字段

      秒表类使用的计时器取决于系统硬件和操作系统。如果秒表计时器基于高分辨率性能计数器,则IsHighResolution 为真。否则 IsHighResolution 为false,表示秒表计时器是基于系统计时器的。

    因此,有不同“类型”的时间具有不同的精度和不同的来源。

    但是,即使这是一个非常松散的逻辑,测试这两种类型的函数作为DATETIME值的来源也证明了这一点。以下对来自问题的查询的改编显示了这种行为:

    DECLARE @Offset DATETIMEOFFSET = SYSDATETIMEOFFSET(),
            @UTC2 DATETIME = SYSUTCDATETIME(),
            @UTC DATETIME = GETUTCDATE();
    DECLARE @UTCFromOffset DATETIME = CONVERT(DATETIME, SWITCHOFFSET(@Offset, 0));
    SELECT
        Offset = @Offset,
        UTC2 = @UTC2,
        UTC = @UTC,
        UTCFromOffset = @UTCFromOffset,
        TimeTravelPossible = CASE WHEN @UTC < @UTCFromOffset THEN 1 ELSE 0 END,
        TimeTravelPossible2 = CASE WHEN @UTC2 < @UTCFromOffset THEN 1 ELSE 0 END;
    

    回报:

    Offset                 2017-06-07 17:50:49.6729691 -04:00
    UTC2                   2017-06-07 21:50:49.673
    UTC                    2017-06-07 21:50:49.670
    UTCFromOffset          2017-06-07 21:50:49.673
    TimeTravelPossible     1
    TimeTravelPossible2    0
    

    正如您在上面的结果中看到的,UTC 和 UTC2 都是DATETIME数据类型。@UTC2通过设置SYSUTCDATETIME()并在之后设置@Offset(也取自 SYS* 函数),但在@UTC此之前设置通过GETUTCDATE(). 然而,@UTC2似乎来之前@UTC。这里的偏移部分与任何东西完全无关。

    然而,公平地说,这仍然不是严格意义上的证明。@MartinSmith 跟踪GETUTCDATE()通话并发现以下内容:

    在此处输入图像描述

    我在这个调用堆栈中看到了三个有趣的东西:

    1. Is 从一个调用开始,该调用GetSystemTime()返回一个精确到毫秒的值。
    2. 它使用 DateFromParts(即没有公式可以转换,只使用单个部分)。
    3. 底部有一个对QueryPerformanceCounter的调用。这是一个高分辨率差异计数器,可用作“校正”的一种手段。我已经看到一些使用一种类型来调整另一种类型的建议,因为长时间间隔会慢慢不同步(请参阅如何在 .NET/C# 中获取刻度精度的时间戳?关于 SO)。这在调用时不会出现SYSDATETIMEOFFSET。

    这里有很多关于不同类型时间、不同来源、漂移等的好信息:Acquiring high-resolution time stamps。

    确实,比较不同精度的值是不合适的。例如,如果你有2017-06-07 12:01:58.8770011和2017-06-07 12:01:58.877,那么你怎么知道精度较低的那个大于、小于或等于精度更高的值?比较它们会假设不太精确的那个实际上是2017-06-07 12:01:58.8770000,但谁知道这是否正确?实际时间可能是2017-06-07 12:01:58.8770005或2017-06-07 12:01:58.8770111。

    但是,如果您有DATETIME数据类型,那么您应该使用 SYS* 函数作为源,因为它们更准确,即使您失去了一些精度,因为值被强制转换为不太精确的类型。沿着这些思路,使用SYSUTCDATETIME()而不是SYSDATETIMEOFFSET()仅通过调用来调整它似乎更有意义SWITCHOFFSET(@Offset, 0)。

    • 9

相关问题

  • SQL Server - 使用聚集索引时如何存储数据页

  • 我需要为每种类型的查询使用单独的索引,还是一个多列索引可以工作?

  • 什么时候应该使用唯一约束而不是唯一索引?

  • 死锁的主要原因是什么,可以预防吗?

  • 如何确定是否需要或需要索引

Sidebar

Stats

  • 问题 205573
  • 回答 270741
  • 最佳答案 135370
  • 用户 68524
  • 热门
  • 回答
  • Marko Smith

    连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目

    • 12 个回答
  • Marko Smith

    如何让sqlplus的输出出现在一行中?

    • 3 个回答
  • Marko Smith

    选择具有最大日期或最晚日期的日期

    • 3 个回答
  • Marko Smith

    如何列出 PostgreSQL 中的所有模式?

    • 4 个回答
  • Marko Smith

    列出指定表的所有列

    • 5 个回答
  • Marko Smith

    如何在不修改我自己的 tnsnames.ora 的情况下使用 sqlplus 连接到位于另一台主机上的 Oracle 数据库

    • 4 个回答
  • Marko Smith

    你如何mysqldump特定的表?

    • 4 个回答
  • Marko Smith

    使用 psql 列出数据库权限

    • 10 个回答
  • Marko Smith

    如何从 PostgreSQL 中的选择查询中将值插入表中?

    • 4 个回答
  • Marko Smith

    如何使用 psql 列出所有数据库和表?

    • 7 个回答
  • Martin Hope
    Jin 连接到 PostgreSQL 服务器:致命:主机没有 pg_hba.conf 条目 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane 如何列出 PostgreSQL 中的所有模式? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh 为什么事务日志不断增长或空间不足? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland 列出指定表的所有列 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney MySQL 能否合理地对数十亿行执行查询? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx 如何监控大型 .sql 文件的导入进度? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison 你如何mysqldump特定的表? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 对 SQL 查询进行计时? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas 如何从 PostgreSQL 中的选择查询中将值插入表中? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas 如何使用 psql 列出所有数据库和表? 2011-02-18 00:45:49 +0800 CST

热门标签

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • 主页
  • 问题
    • 最新
    • 热门
  • 标签
  • 帮助

Footer

AskOverflow.Dev

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve