SQL 服务器 CLR 线程
SQL Server CLR Threading
我一直在努力使用 SQL 服务器 CLR 存储过程。
背景:
我们正在使用 SQL Server 2014,并且已经实现了调用客户 Web 服务的 CLR 存储过程。
线程最初用于不减慢 SQL 服务器 CLR 的主线程。
虽然现在我知道在 CLR 下使用线程并不是最好的主意,但它已经正常工作了 6 年(自 SQL Server 2008 以来)。它最近已迁移到 SQL Server 2014。
问题
在我的开发机器上,与在测试系统上一样,我们的解决方案没有问题。
在客户系统上,调用网络服务的线程由于某种原因从未执行过。
我可以从日志文件中看到在线程执行之前一切正常。
没有具体的错误,没有。
我们一直在尝试更改权限,但没有成功。因此我认为这不是权限问题。
问题
有谁知道如何改变这种行为?我们找不到任何可以解决问题的配置。
完全删除线程并直接在 SQL 服务器主线程上调用 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。由于您没有看到错误而您的客户看到了,我会确保他们的系统已更新到与您 运行ning.
相同的 .NET Framework 版本
对于问题 #2,我建议删除多线程。这有太多潜在的问题,需要大会 UNSAFE
。如果删除线程,则可以将 Assembly 设置为 EXTERNAL_ACCESS
.
如果您想减少争用,假设 Web 服务调用是针对相同的 URI,那么您需要增加允许的并发 Web 请求数。这可以通过设置 ServicePointManager.DefaultConnectionLimit Property 来完成。默认值为 2。这意味着,任何额外的请求都会等待,直到当前 2 个中的一个关闭。
另外,一定要正确Dispose
的WebRequest
。
关于进行可能无法快速完成的外部调用(即 Web 服务)的担忧是 SQL 服务器使用协作式多任务处理,其中每个线程负责 "yielding" 将控制权返回给调度程序(有效地暂停它)在不同的点,以便调度程序可以随机播放和 运行 当前 "sleeping" 的其他内容。这种与 SQLCLR 代码相关的担忧通常可以通过至少执行以下操作之一来缓解:
- 执行数据访问/查询实例
- 呼叫
thread.sleep(0);
但是,外部调用不进行数据访问,您不能在等待 WebResponse
完成时轻易调用 thread.sleep(0)
。是的,您可以在单独的线程上调用 WebService 并在等待它完成时假设您只是循环和检查,sleep(x)
将允许收益。
但是有必要异步调用 Web 服务吗?它当然有要求 Assembly 标记为 WITH PERMISSION_SET = UNSAFE
的缺点。这在很大程度上取决于通话通常需要多长时间,以及通话的频率。调用越频繁,任何延迟越有可能至少部分是由每个 URI 允许的并发连接数的低默认值引起的。这与我在顶部提出的建议有关。
但是如果您想了解 SQL 服务器实际如何工作,这应该很容易测试。在我的笔记本电脑上,我转到对象资源管理器中的服务器 "Properties",然后转到 "Processors",取消选中 "automatically set processor affinity..." 选项,仅在 "Processor Affinity" 下选择一个 CPU在对话框中间的树视图中,单击 "OK",然后重新启动服务。然后我设置了一个网页,除了调用 "sleep" 60 秒之外什么都不做。我有一个调用网页的 SQLCLR TVF,所以我 运行 同时在两个不同的选项卡/会话中。在第 3 个选项卡/会话中,我 运行:
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 个会话的状态始终是 "running",运行使用选项卡 3 中那个丑陋查询的会话的状态始终是 "running"总是 "runnable"。但可以肯定的是,当 SQLCLR 函数都没有执行时,再次 运行ning 那个丑陋的查询所花费的时间与 运行ning 同时执行时相同的 1 分 14 秒通过 2 个会话 运行 对休眠 60 秒的网页进行 SQLCLR 调用。
请不要推断没有 运行使用SQLCLR 代码进行网络调用的成本。由于这些线程一直很忙,如果系统很忙,那么 SQL 服务器分配这些线程以更快地完成其他查询的能力就会降低。但是可以肯定地得出这样的结论,至少在低到中等负载的系统上,通过添加线程获得的好处似乎不值得增加复杂性的成本(特别是因为现在有一个尚未重现的要调试的问题)。
我一直在努力使用 SQL 服务器 CLR 存储过程。
背景:
我们正在使用 SQL Server 2014,并且已经实现了调用客户 Web 服务的 CLR 存储过程。
线程最初用于不减慢 SQL 服务器 CLR 的主线程。
虽然现在我知道在 CLR 下使用线程并不是最好的主意,但它已经正常工作了 6 年(自 SQL Server 2008 以来)。它最近已迁移到 SQL Server 2014。
问题
在我的开发机器上,与在测试系统上一样,我们的解决方案没有问题。
在客户系统上,调用网络服务的线程由于某种原因从未执行过。
我可以从日志文件中看到在线程执行之前一切正常。
没有具体的错误,没有。
我们一直在尝试更改权限,但没有成功。因此我认为这不是权限问题。
问题
有谁知道如何改变这种行为?我们找不到任何可以解决问题的配置。
完全删除线程并直接在 SQL 服务器主线程上调用 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。由于您没有看到错误而您的客户看到了,我会确保他们的系统已更新到与您 运行ning.
相同的 .NET Framework 版本对于问题 #2,我建议删除多线程。这有太多潜在的问题,需要大会 UNSAFE
。如果删除线程,则可以将 Assembly 设置为 EXTERNAL_ACCESS
.
如果您想减少争用,假设 Web 服务调用是针对相同的 URI,那么您需要增加允许的并发 Web 请求数。这可以通过设置 ServicePointManager.DefaultConnectionLimit Property 来完成。默认值为 2。这意味着,任何额外的请求都会等待,直到当前 2 个中的一个关闭。
另外,一定要正确Dispose
的WebRequest
。
关于进行可能无法快速完成的外部调用(即 Web 服务)的担忧是 SQL 服务器使用协作式多任务处理,其中每个线程负责 "yielding" 将控制权返回给调度程序(有效地暂停它)在不同的点,以便调度程序可以随机播放和 运行 当前 "sleeping" 的其他内容。这种与 SQLCLR 代码相关的担忧通常可以通过至少执行以下操作之一来缓解:
- 执行数据访问/查询实例
- 呼叫
thread.sleep(0);
但是,外部调用不进行数据访问,您不能在等待 WebResponse
完成时轻易调用 thread.sleep(0)
。是的,您可以在单独的线程上调用 WebService 并在等待它完成时假设您只是循环和检查,sleep(x)
将允许收益。
但是有必要异步调用 Web 服务吗?它当然有要求 Assembly 标记为 WITH PERMISSION_SET = UNSAFE
的缺点。这在很大程度上取决于通话通常需要多长时间,以及通话的频率。调用越频繁,任何延迟越有可能至少部分是由每个 URI 允许的并发连接数的低默认值引起的。这与我在顶部提出的建议有关。
但是如果您想了解 SQL 服务器实际如何工作,这应该很容易测试。在我的笔记本电脑上,我转到对象资源管理器中的服务器 "Properties",然后转到 "Processors",取消选中 "automatically set processor affinity..." 选项,仅在 "Processor Affinity" 下选择一个 CPU在对话框中间的树视图中,单击 "OK",然后重新启动服务。然后我设置了一个网页,除了调用 "sleep" 60 秒之外什么都不做。我有一个调用网页的 SQLCLR TVF,所以我 运行 同时在两个不同的选项卡/会话中。在第 3 个选项卡/会话中,我 运行:
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 个会话的状态始终是 "running",运行使用选项卡 3 中那个丑陋查询的会话的状态始终是 "running"总是 "runnable"。但可以肯定的是,当 SQLCLR 函数都没有执行时,再次 运行ning 那个丑陋的查询所花费的时间与 运行ning 同时执行时相同的 1 分 14 秒通过 2 个会话 运行 对休眠 60 秒的网页进行 SQLCLR 调用。
请不要推断没有 运行使用SQLCLR 代码进行网络调用的成本。由于这些线程一直很忙,如果系统很忙,那么 SQL 服务器分配这些线程以更快地完成其他查询的能力就会降低。但是可以肯定地得出这样的结论,至少在低到中等负载的系统上,通过添加线程获得的好处似乎不值得增加复杂性的成本(特别是因为现在有一个尚未重现的要调试的问题)。