SQL Server CLR线程

我一直在努力使用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服务是不是一个好主意?

谢谢你的任何建议,彼得

对问题#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,我建议删除multithreading。 这有太多潜在的问题,需要大会成为联合国UNSAFE 。 如果删除线程,则可以将Assembly设置为EXTERNAL_ACCESS

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

另外,请务必正确Dispose WebRequest


关于进行可能无法快速完成的外部调用(即Web服务)的担忧是SQL Server使用协作式多任务处理,其中每个线程负责在各个​​点处“控制”控制回到调度程序(有效地暂停它),以便调度程序可以随机播放并运行其他正在“hibernate”的内容。 通常可以通过执行以下至少一项来减轻对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; 

运行SQLCLRfunction的2个会话的状态始终为“正在运行”,并且在选项卡3中运行该丑陋查询的会话的状态始终为“可运行”。 但只是为了确定,当两个SQLCLR函数都没有执行时,再次运行那个丑陋的查询,与运行SQLCLR调用的2个会话同时运行时所执行的1分14秒相同。持续60秒。

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