如何强制生成新的 sysdatetime()?

Posted

技术标签:

【中文标题】如何强制生成新的 sysdatetime()?【英文标题】:How to force generation of a new sysdatetime()? 【发布时间】:2019-05-20 10:23:39 【问题描述】:

我尝试创建一个函数来根据来自this solution 的时间戳生成bigint UID。虽然准确度应该足以避免冲突,但服务器显然不会在每次调用时测量sysdatetime() 返回的datetime2。在一个循环中,我能够在更改发生之前生成数十个相同的 UID。我不确定它在内部是如何工作的,但是有什么方法可以强制每次调用都生成一个新的datetime2

create function [func].GenerateBigIntID()
returns bigint
as
begin
  declare @Binary binary(9) = cast(reverse(cast(sysdatetime() as binary(9))) as binary(9)) 
  return(select cast(substring(@Binary, 1, 3) as bigint) * 864000000000 + cast(substring(@Binary, 4, 5) as bigint))
end

【问题讨论】:

如果循环足够紧,sysdatetime() 将在不止一次迭代中返回相同的值,因为两者之间没有足够的时间经过。对此你无能为力。为什么不直接使用sequence? 每次调用sysdatetime 时都会在该时间点进行评估。如果您有查询SELECT sysdatetime(),sysdatetime(),sysdatetime(),sysdatetime(),sysdatetime(),,那么它将评估它 5 次;只是所有 5 个值都将与同时评估的值相同。这听起来像是一个 XY 问题。另外,您说您正在使用循环;为什么? SQL Server 擅长数据集方法,而不是迭代方法。 @Larnu 通常,我有连续的命令,每个命令都使用这个函数,有时我会收到关于重复键的错误,所以我尝试在循环中运行该函数只是为了测试看看多久它会改变。 为什么不改用uniqueidentifier 之类的东西? T-SQL 部分依赖于此处操作系统提供的时钟分辨率(通常约为 15 毫秒),此外还有关于与其他实例缓存/统一的值的任何担忧由优化器,并且没有 T-SQL 函数来访问高分辨率时间戳(即使假设它可用)。根据经验,WAITFOR DELAY '00:00:00.01'“足够长”以强制增量,但当然这种行为远不能保证。使用标识列 NEWSEQUENTIALID()SEQUENCE 或与 CRYPT_GEN_RANDOM 结合使用(用于“大部分顺序”值)。 【参考方案1】:

短版:不,这是不可能的。如果循环足够紧,SysDateTime 将在循环的多次迭代中返回相同的值。

长版:

SysDateTime() 将当前日期和时间返回为DateTime2(7)。 它通过使用GetSystemTimeAsFileTime()win-api 函数获取当前日期和时间值。 这意味着即使它以 100 纳秒的精度返回 DateTime2,返回值的实际精度取决于运行 SQL Server 实例的计算机硬件和 Windows 版本。

我猜在一台可以从该 win-api 函数获得非常准确的结果但在 SQL 中执行慢速循环的计算机上,您可能能够在循环中获得唯一的 id - 但是,我不能甚至猜测您需要什么样的硬件、Windows 版本和常规设置(或者如果可能的话)。

从 2012 版本开始,生成唯一 bigint 值而不依赖于对表的插入的最佳方法是使用 sequence

【讨论】:

以上是关于如何强制生成新的 sysdatetime()?的主要内容,如果未能解决你的问题,请参考以下文章

如何强制为特定 PHP 版本创建新的 Symfony 应用程序?

如何强制 Flutter 使用新的开发者证书?

如何为包括旧资产在内的所有资产强制使用新指纹?

SQL精华应用

如何强制电报更新链接预览?

如何强制等宽字体在 Facebook 中呈现?