不确定问题#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
of the WebRequest
.
对可能无法快速完成的外部调用(即 Web 服务)的担忧是,SQL Server 使用协作多任务处理,其中每个线程负责在不同点将控制权“让渡”回调度程序(有效地暂停它),以便调度程序可以打乱事物的顺序并运行当前“睡眠”的其他事物。对于 SQLCLR 代码的这种担忧通常可以通过执行以下至少一项操作来缓解:
- 执行数据访问/查询实例
- Calling
thread.sleep(0);
但是,外部调用并不是进行数据访问,不能轻易调用thread.sleep(0)
在等待的同时WebResponse
去完成。是的,您可以在单独的线程上调用 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;
最后,在第四个选项卡中,启动前 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 个会话同时运行时所花费的时间相同60 秒。
请不要推断有no运行 SQLCLR 代码以进行 Web 调用的成本。由于这些线程一直很忙,如果系统很忙,那么 SQL Server 分配这些线程以更快地完成其他查询的能力就会降低。但似乎确实可以得出这样的结论:至少在低负载到中等负载的系统上,通过添加线程获得的好处似乎不值得增加复杂性的成本(特别是因为现在有一个尚未重现的需要调试的问题)。