为什么这两个查询会产生不同的结果(但彼此相差大约一分钟)?
SELECT StartTime = sqlserver_start_time
FROM sys.dm_os_sys_info;
SELECT StartTime = DATEADD(MILLISECOND, sqlserver_start_time_ms_ticks - ms_ticks, GETDATE())
FROM sys.dm_os_sys_info;
哪个更准确?
为什么这两个查询会产生不同的结果(但彼此相差大约一分钟)?
SELECT StartTime = sqlserver_start_time
FROM sys.dm_os_sys_info;
SELECT StartTime = DATEADD(MILLISECOND, sqlserver_start_time_ms_ticks - ms_ticks, GETDATE())
FROM sys.dm_os_sys_info;
哪个更准确?
两者都不是最准确的 [A],但是如果你只有这两个选择,那么可疑的日期计算似乎确实会更准确一些 [C]。
它们似乎以两种不同的方式存储 [B],并且没有进入超深(但足够深)的额外处理时间以及它们的设置位置,以及在第 3 方模块中花费的时间弥补了差异。
深潜
[A] 最准确的进程启动时间是 Windows 对进程结构的了解,可以通过 powershell 或 WinAPI 轻松查询。我在调试器下启动 SQL Server,看看是否有一种简单的方法可以解决这个问题,因为我可以添加任何我想要的时间延迟。考虑到诸如开始时间/滴答之类的东西作为一个更全局的项目来跟踪是有意义的,我尝试使用公共符号来查看我是否可以找到它并人为地引入一个合适的时间间隔。下图是在调试器下启动进程的时间,根据Windows,这是最准确的时间——11/22/2022 11:46:23 AM,我们回头参考这个值。
[B] 然后我检查了 sqldk 中任何内容的公共符号导出,因为这是本质上执行 SQL 操作系统初始化的 dll,作为获取/设置启动信息或时间的地方最有意义。
事实上,有一些看起来很有趣的命中,以及一些可能是设置断点的好地方的函数。请注意,突出显示的值似乎与 DMV 相当匹配。
[C] 在调试器下重新启动进程,
ba
为两个看似全局的值设置项目并在 sqldk 模块加载时设置中断。Ticks 和 Time 在函数中设置在基本相同的区域sqldk!SOS_OS::InitOs
,但是对于TimeWhenSOSBooted
值,调用内核中的GetSystemTimeAsFileTime这将花费额外的处理时间并且另外可以绕道,以及反*程序使用的其他方法。由于我能够添加延迟,因此最终结果如下。
因此,似乎首先设置了刻度,并且两个值之间更准确(甚至考虑了舍入和数学问题)但在整体方案中并不准确,因为这属于我引入的 Windows 进程创建时间值整整1+分钟的时差。