SQL CLR Web 服务调用:限制开销
SQL CLR Web Service Call: Limiting Overhead
我正在尝试提高应用程序的查询性能,但逻辑上卡住了。
因此该应用程序是专有的,因此我们无法更改应用程序端代码。然而,我们已经获得了使用底层数据库的许可(足够令人惊讶)。该应用程序调用 SQL 服务器数据库,因此我们目前的想法 运行 是创建一个与 table 同名的视图并重命名底层 table。当应用程序访问视图时,视图会调用两个 SQL CLR 函数之一,这两个函数只不过是调用我们放在一起的 Web 服务。 Web 服务执行所有逻辑,并包含对外部专有 API 的 API 调用,后者执行一些额外的逻辑,然后 returns 结果。
一切正常,但是,在扩展到大型数据集(超过 100,000 行)时,我们遇到了严重的性能问题。很明显的来源是我们必须使用 Web 服务一次处理一行,其中包括 API 调用,这会产生大量延迟开销。
解决这个问题的明显方法是找出一种方法来限制每次查询必须访问 Web 服务的次数,但这就是我遇到的问题。我已经阅读了一些可能处理这种情况的不同方法,但作为一个完全的数据库新手,我很难掌握在这种情况下什么是合适的。
如果有 ideas/recommendations,我将不胜感激。
这里大概有几点要看:
您的 SQLCLR TVF 是否将结果流出(即您是添加到一个集合然后在最后 returning 该集合,还是您发布每个完成时的行 - 使用 yield return
或构建完整的枚举器)?如果不是流式传输,那么您应该这样做,因为它允许立即使用行,而不是等待整个过程完成。
由于您将 Table 替换为源自 TVF 的视图,因此您自然会遇到性能下降,因为 TVF:
- 不要报告它们的实际行数。 T-SQL 多语句 TVF 总是出现在 return 1 行,SQLCLR TVF 总是出现在 return 1000 行。
- 不维护列统计信息。从 Table 中选择时,SQL 服务器将自动为
WHERE
和 JOIN
条件中引用的列创建统计信息。
由于这两件事,如果实际行数为 100k,查询优化器将不会轻松生成适当的计划。
有多少 SELECT
等同时点击此视图?由于视图每次都访问相同的 URI,因此您受到 ServicePointManager ( ServicePointManager.DefaultConnectionLimit ) 强加的并发连接限制的约束。而且默认限制高达 2
!意思是,当已经有 2 active/open HttpWebRequest
s 时,对该 URI 的所有额外请求都将耐心地内联等待。您可以通过设置 HttpWebRequest
对象的 .ServicePoint.ConnectionLimit
属性 来增加它。
基础数据多久更改一次?由于您切换到一个视图,它不接受任何参数,因此您总是 return 处理所有内容。这为进行一些缓存打开了大门,并且有两个选项(至少):
- 在 Web 服务中缓存数据,如果未达到特定时间限制,return 缓存数据,否则获取新数据,缓存它,然后 return。
- 回去使用真正的 Table。创建一个 SQL 服务器代理作业,每隔几分钟(如果数据不经常更改,则可能更长时间):启动事务,删除当前数据,通过 SQLCLR TVF 重新填充,并提交事务。这需要 SQL 代理工作的额外部分,但您随后将获得更准确的统计信息!
有关使用 SQLCLR 的更多信息,请访问:SQLCLR Info
我正在尝试提高应用程序的查询性能,但逻辑上卡住了。
因此该应用程序是专有的,因此我们无法更改应用程序端代码。然而,我们已经获得了使用底层数据库的许可(足够令人惊讶)。该应用程序调用 SQL 服务器数据库,因此我们目前的想法 运行 是创建一个与 table 同名的视图并重命名底层 table。当应用程序访问视图时,视图会调用两个 SQL CLR 函数之一,这两个函数只不过是调用我们放在一起的 Web 服务。 Web 服务执行所有逻辑,并包含对外部专有 API 的 API 调用,后者执行一些额外的逻辑,然后 returns 结果。
一切正常,但是,在扩展到大型数据集(超过 100,000 行)时,我们遇到了严重的性能问题。很明显的来源是我们必须使用 Web 服务一次处理一行,其中包括 API 调用,这会产生大量延迟开销。
解决这个问题的明显方法是找出一种方法来限制每次查询必须访问 Web 服务的次数,但这就是我遇到的问题。我已经阅读了一些可能处理这种情况的不同方法,但作为一个完全的数据库新手,我很难掌握在这种情况下什么是合适的。
如果有 ideas/recommendations,我将不胜感激。
这里大概有几点要看:
您的 SQLCLR TVF 是否将结果流出(即您是添加到一个集合然后在最后 returning 该集合,还是您发布每个完成时的行 - 使用
yield return
或构建完整的枚举器)?如果不是流式传输,那么您应该这样做,因为它允许立即使用行,而不是等待整个过程完成。由于您将 Table 替换为源自 TVF 的视图,因此您自然会遇到性能下降,因为 TVF:
- 不要报告它们的实际行数。 T-SQL 多语句 TVF 总是出现在 return 1 行,SQLCLR TVF 总是出现在 return 1000 行。
- 不维护列统计信息。从 Table 中选择时,SQL 服务器将自动为
WHERE
和JOIN
条件中引用的列创建统计信息。
由于这两件事,如果实际行数为 100k,查询优化器将不会轻松生成适当的计划。有多少
SELECT
等同时点击此视图?由于视图每次都访问相同的 URI,因此您受到 ServicePointManager ( ServicePointManager.DefaultConnectionLimit ) 强加的并发连接限制的约束。而且默认限制高达2
!意思是,当已经有 2 active/openHttpWebRequest
s 时,对该 URI 的所有额外请求都将耐心地内联等待。您可以通过设置HttpWebRequest
对象的.ServicePoint.ConnectionLimit
属性 来增加它。基础数据多久更改一次?由于您切换到一个视图,它不接受任何参数,因此您总是 return 处理所有内容。这为进行一些缓存打开了大门,并且有两个选项(至少):
- 在 Web 服务中缓存数据,如果未达到特定时间限制,return 缓存数据,否则获取新数据,缓存它,然后 return。
- 回去使用真正的 Table。创建一个 SQL 服务器代理作业,每隔几分钟(如果数据不经常更改,则可能更长时间):启动事务,删除当前数据,通过 SQLCLR TVF 重新填充,并提交事务。这需要 SQL 代理工作的额外部分,但您随后将获得更准确的统计信息!
有关使用 SQLCLR 的更多信息,请访问:SQLCLR Info