gpt4 book ai didi

c# - SQL Server CLR 集成未按预期调用系统时间

转载 作者:行者123 更新时间:2023-11-30 20:38:13 50 4
gpt4 key购买 nike

先了解一下背景,然后才是具体问题。

我正在尝试生成顺序 GUID 以用作 SQL Server 2008 R2 表中的主要 ID。以前,这些是由用户定义的函数生成的,该函数执行过多的字符串操作以生成顺序 GUID,这是一个性能瓶颈。

为了尝试减少此函数的时间,我尝试使用 CLR 集成并在 C# 类中执行操作。 GUID 的序列化是通过更新最后一个 12 bytes 来完成的。 GUID 到从系统日期时间生成的值。

在初始版本中,GetUTCDate() SQL Server 系统函数用于获取日期时间并将其转换为刻度,然后用于创建连续的 12 个字节的 guid。我的方法是使用 .NET Framework DateTime.UtcNow.Ticks 属性转换为最后 12 个字节,但我注意到 Ticks 属性没有更新为预期,这表明系统时间功能没有像我预期的那样经常被调用。

为了对此进行测试,我创建了一个返回 Ticks 的简单方法:

[SqlFunction()]
public static long GetTicks()
{
return DateTime.UtcNow.Ticks;
}

此方法的此程序集随后创建为 ASSEMBLY SQL Server 中的对象;请注意,启用了 CLR 集成并且程序集是在 UNSAFE 模式下创建的,因此允许访问 OS APIs .然后我在 SQL Server 中为这个 CLR 函数创建了一个函数:

CREATE FUNCTION GetTicks() RETURNS BIGINT 
AS EXTERNAL NAME Sequential.Generator.GetTicks;
GO

然后我执行了以下两个语句,结果如下所示

SELECT [dbo].[GetTicks]();
SELECT [dbo].[GetTicks]();

结果是:

enter image description here

这表明对 CLR 函数的顺序调用返回了相同的 TICKS 值。这意味着未执行底层操作系统调用以在每次调用 GetTicks() 函数时返返回价。然后我通过创建一个像这样的简单表来执行第二个测试:

CREATE TABLE #tmp1(
[NUM] [INT] NULL,
[TICKS] BIGINT
);

我用 300 行填充了表,然后执行了以下语句:

UPDATE #tmp1
SET [ticks] = [Play].[dbo].[GetTicks]();

然后我测量了连续行的 [ticks] 值之间的差异,并且在所有 300 行中只有一个值发生变化(在 Excel 中完成):

enter image description here

同样,这表明框架 DateTime.UtcNow.Ticks 属性并未在每次调用 CLR 集成函数 GetTicks() 时被调用。

  1. 有没有一种方法可以启用 CLR 集成,以便可以在每次从 SQL Server 调用函数时执行对底层操作系统的调用?

  2. SQL CLR 集成是否是 SQL Server 以比 GetUTCDATE() T-SQL 函数更频繁的方式从操作系统检索系统时间的不明智方法?

谢谢!

(*) 请注意,顺序 GUID 是必需的,我只是想最大限度地提高它们生成方式的性能。此外,NEWSEQUENTIALID()由于隐私问题,该功能不被接受。

最佳答案

Again, this indicates the Framework DateTime.UtcNow.Ticks property was not being called for each invocation of the CLR Integrated function GetTicks().

不,它并不表示未调用 UtcNow 属性。问题是 .NET 中 System.DateTime 的解析。无论该值有多精确,该值仅每 10 - 16 毫秒递增一次(类似于 T-SQL 中的 GETDATE() 仅每 3 毫秒更新一次)。这就是为什么该值对于一定数量的行保持不变,但不像 T-SQL 日期时间函数那样跨所有行(例如 GETDATE() 等)。

Is there a way to enable CLR Integration such that calls to the underlying OS can performed with each invocation of a function from SQL Server?

“CLR 集成”功能处于“启用”或“禁用”状态。除此之外没有它的配置。正如上面直接提到的,这是 DateTime.UtcNow.Ticks 的值更新频率的问题。

Is SQL CLR Integration an unwise approach for SQL Server to retrieve the system time from the OS on a basis more frequent than the GetUTCDATE() T-SQL function?

不像使用 GUID/UNIQUEIDENTIFIER 作为 PK 那样不明智(我假设它是聚簇索引),这本身并不像试图减轻由以下内容导致的性能问题那样不明智然后通过引入非内置函数来做出该决定。

当前的UDF是如何被调用生成值的? INSERT 触发器?

如果性能是个问题,那么将 PK 设为 INTBIGINT 并使用 IDENTITY。保留 GUID 字段,但通过向其添加 NonClustered 索引使其成为“备用键”。应用程序代码可以使用 GUID 值,但 JOIN 等应使用 INT/BIGINT PK。

但是,就获取更频繁更改的 DateTime.UtcNow.Ticks 值 而言,从 Windows 8/Windows Server 2012 开始,有一个新的操作系统函数 GetSystemTimePreciseAsFileTime ,这将适用于此。通常我会补充说,“不幸的是,它要求将程序集标记为不安全”,因为除非绝对必要,否则应该避免这种情况,但是你已经提到将你的程序集标记为 UNSAFE 所以这不会改变那个。

为了使用这个新功能,只需从这里获取代码:

High Resolution Clock in C#

然后替换:

DateTime.UtcNow.Ticks

与:

HighResolutionDateTime.UtcNow.Ticks

!! 请注意:SQL Server 不保证调用函数的次数。这意味着,多次调用此函数(或任何函数,包括 NEWID())可能,即使极不可能,也会返回相同的值,即使特别是声明为 IsDeterministic = false。然而,这也适用于 T-SQL UDF,因此如果进程当前正在使用 T-SQL UDF,那么一旦切换为 SQLCLR 标量函数,它应该继续工作。

关于c# - SQL Server CLR 集成未按预期调用系统时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35344762/

50 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com