高效交叉应用CLR集成表功能

时间:2013-01-15 15:16:40

标签: sql-server sqlclr cross-apply

在SQL Server中,我有一个基于CLR集成的表值函数GetArchiveImages。我称之为:

SELECT ...
FROM Items
CROSS APPLY GetArchiveImages(Items.ID) AS archiveimages
WHERE ...

问题是每次调用该函数都会产生开销。

如果它可以同时与整个表连接,那么开销就会很小,但由于每行调用一次,所以开销与行数一致。

我不使用存储过程,因为存储过程返回的表不能与任何东西连接(据我所知)。

是否有一种有效的方法将表与存储过程或函数的结果批量连接,而不是逐行连接?

2 个答案:

答案 0 :(得分:2)

由于GetArchiveImages的结果取决于Items.ID,SQL Server必须为每个项目调用该函数,否则您将无法获得正确的结果。

SQL Server可以“分解”的唯一功能是T-SQL内联表值函数。因此,如果您可以将CLR重写为ITVF,您将获得更好的性能。

根据我的经验,调用CLR函数的过多并不是那么大。您更有可能在查询中的其他位置遇到问题。例如,SQL Server不知道该函数将返回多少行,并假设它将是一个(对于每个调用)。在优化过程中,这可能导致其他地方的错误决策。


更新:

SQL Server不允许在CLR类中保留静态非常量数据。有办法欺骗系统,例如通过创建静态最终集合对象(您可以添加和删除静态集合中的项目),但是,出于稳定性原因,我建议不要这样做。

在您的情况下创建一个缓存表可能是有意义的,该缓存表可以使用某种(数据库或文件系统)触发器或按计划自动刷新。您可以加入该表,而不是调用该函数。

答案 1 :(得分:1)

如果GetArchiveImages()函数不需要在多个查询中使用,或者至少不在类似查询之外使用,则可以切换此外部和内部方面:执行主SELECT fields FROM [Items] WHERE ...在SQLCLR TVF中。并使其成为流媒体TVF。

所需的基本结构是:

  1. 将SqlDataRecord类型的变量定义为要从[Items]返回的所有字段以及当前GetArchiveImages()函数返回的其他字段。

  2. 阅读"文件系统中的几个文件" (摘自@Sebastian Meine的第一条评论&#39>

  3. 使用"Trusted_Connection = true; Enlist = false;"作为ConnectionString打开SqlConnection。

  4. 执行主SELECT fields FROM [Items] {optional WHERE}。如果此时可以缩小部分行,请填写WHERE。您甚至可以将值传递给函数以传递给WHERE子句。

  5. 循环浏览SqlDataRecord

    1. 填写此行的SqlDataRecord变量
    2. 根据GetArchiveImages()
    3. 获取当前[Items].[ItemID]功能获取的相关项目
    4. 致电yield return;
  6. 关闭SqlConnection

  7. 弃置SqlDataReaderSqlCommandSqlConnection

  8. 关闭在步骤2中打开的所有文件(如果在此过程中无法关闭它们)。