如何强制生成新的 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()?的主要内容,如果未能解决你的问题,请参考以下文章