SQL Server CLR Threading

本文关键字:Threading CLR Server SQL | 更新日期: 2023-09-27 18:32:42

我一直在为SQL Server CLR存储过程而苦苦挣扎。

背景:

我们使用的是 SQL Server 2014,并且已实现调用客户的 Web 服务的 CLR 存储过程。

线程最初用于不减慢 SQL Server CLR 的主线程。

虽然,现在,我知道在CLR下使用线程不是最好的主意,但它已经正常工作了6年(自SQL Server 2008以来(。它最近已迁移到SQL Server 2014。

问题所在

在我的开发机器上,与在测试系统上一样,我们的解决方案没有问题。

在客户系统上,由于某种原因,调用 Web 服务的线程永远不会执行。

我可以从日志文件中看到,在线程执行之前一切正常。

没有特定的错误,什么都没有。

我们一直在尝试更改权限,但没有成功。因此,我认为这不是权限问题。

问题

  1. 有谁知道如何改变行为?我们找不到任何可能解决问题的配置。

  2. 完全删除线程并直接在 SQL Server 主线程上调用 Web 服务是个好主意吗?

谢谢你的任何建议,切赫

SQL Server CLR Threading

不确定问题 #1,尽管考虑到问题 #2 的建议可能无关紧要。尽管如此,SQL Server 2008(它正在工作的地方(和SQL Server 2014(它不工作的地方(之间的一个区别是SQL Server链接到的CLR版本。SQL Server 2005/2008/2008 R2链接到CLR v2.0,而SQL Server 2012及更高版本链接到CLR v 4.0。由于您没有看到错误,而您的客户端是,我将确保他们的系统已更新到您正在运行的相同.NET Framework版本。

对于问题#2,我建议删除多线程。这有太多可能出现问题,需要大会UNSAFE。如果删除螺纹,则可以将程序集设置为 EXTERNAL_ACCESS

如果要减少争用,则假定 Web 服务调用是针对同一 URI,则需要增加允许的并发 Web 请求数。这可以通过设置 ServicePointManager.DefaultConnectionLimit 属性来完成。默认值为 2。这意味着,任何其他请求都将等待并等待,直到当前 2 个请求中的一个关闭。

另外,请务必正确Dispose WebRequest


对于进行可能无法快速完成的外部调用(即 Web 服务(的担忧是,SQL Server 使用协作多任务处理,其中每个线程负责在不同点将控制权"交出"回调度程序(有效地暂停它(,以便调度程序可以打乱事情并运行当前"休眠"的其他内容。通常可以通过执行以下至少一项操作来缓解有关 SQLCLR 代码的这种担忧:

  • 执行数据访问/查询实例
  • 呼叫thread.sleep(0);

但是,外部调用不执行数据访问,并且在等待WebResponse完成时无法轻松调用thread.sleep(0)。是的,您可以在单独的线程上调用 WebService,并在等待它完成时,假设您只是循环和检查,sleep(x)将允许产量。

但是,异步执行 Web 服务调用是否必要?它当然有要求将大会标记为WITH PERMISSION_SET = UNSAFE的缺点。这在很大程度上取决于呼叫通常需要多长时间以及呼叫频率。调用越频繁,任何延迟(至少部分(由每个 URI 允许的并发连接数的默认值较低引起的可能性就越大。这与我在顶部提出的建议有关。

但是,如果你想看看SQL Server的实际工作原理,这应该很容易测试。在我的笔记本电脑上,我转到对象资源管理器中的服务器"属性",转到"处理器",取消选中"自动设置处理器关联..."选项,在对话框中间的树视图中的"处理器关联"下仅选择单个 CPU,单击"确定",然后重新启动服务。然后,我设置了一个网页,除了调用"睡眠"60秒之外什么都不做。我有一个调用网页的 SQLCLR TVF,所以我在两个不同的选项卡/会话中同时运行它。在第三个选项卡/会话中,我运行了:

SELECT SUM(so1.[schema_id]), so1.[type_desc], so2.[type_desc]
FROM sys.objects so1
CROSS JOIN sys.objects so2
CROSS JOIN sys.objects so3
CROSS JOIN sys.objects so4
CROSS JOIN sys.objects so5
WHERE so3.[create_date] <> so4.[modify_date]
GROUP BY so1.[type_desc], so2.[type_desc], so5.[name]
ORDER BY so2.[type_desc], so5.[name] DESC;

最后,在第 4 个选项卡中,在启动前 3 个选项卡后,我运行以下命令来监控系统:

SELECT * FROM sys.dm_os_schedulers WHERE [scheduler_id] = 0;
SELECT *
FROM sys.dm_exec_requests
WHERE [scheduler_id] = 0
AND [status] <> N'background'
ORDER BY [status] DESC, session_id;

运行 SQLCLR 函数的 2 个会话的状态始终为"正在运行",而运行选项卡 3 中该丑陋查询的会话的状态始终为"可运行"。但可以肯定的是,当两个 SQLCLR 函数都没有执行时,再次运行这个丑陋的查询所花费的时间与与运行 SQLCLR 调用的 2 个会话同时运行时花费的 1 分 14 秒相同,该会话对休眠的网页进行了 60 秒。

请不要推断运行 SQLCLR 代码进行 Web 调用没有成本。由于这些线程一直处于繁忙状态,因此如果系统繁忙,则会降低 SQL Server 分配这些线程以更快地完成其他查询的能力。但似乎可以肯定的是,至少在负载低到中等的系统上,通过添加线程获得的好处似乎不值得增加复杂性的成本(特别是因为现在有一个尚未重现的问题需要调试(。