Sql server 加入构建临时表的TVF比加入straight子句快得多。为什么会这样?

Sql server 加入构建临时表的TVF比加入straight子句快得多。为什么会这样?,sql-server,indexing,sql-server-2012,sql-server-2016,Sql Server,Indexing,Sql Server 2012,Sql Server 2016,我们正在优化一个看起来设计糟糕的查询。有一个多行表值函数的连接,很容易成为内联函数,所以我们对它进行了更新。。但是查询变得慢多了。多行函数返回一个主键为单列的临时表,而内联TVF只返回一个直接的单列表 进行了一点研发,我们发现使用多行连接的TVF作为子句可以获得很大的性能提升。下面的示例可以针对任何数据库运行,最好是对象更新历史较长的数据库。第一个查询是我们认为最好的设计,但第二个查询的性能要好得多(通常快20倍)。这实际上是查询成本,而不是速度 函数和查询与我们在系统上处理的函数和查询类似,但

我们正在优化一个看起来设计糟糕的查询。有一个多行表值函数的连接,很容易成为内联函数,所以我们对它进行了更新。。但是查询变得慢多了。多行函数返回一个主键为单列的临时表,而内联TVF只返回一个直接的单列表

进行了一点研发,我们发现使用多行连接的TVF作为子句可以获得很大的性能提升。下面的示例可以针对任何数据库运行,最好是对象更新历史较长的数据库。第一个查询是我们认为最好的设计,但第二个查询的性能要好得多(通常快20倍)。这实际上是查询成本,而不是速度

函数和查询与我们在系统上处理的函数和查询类似,但这里我们用一个系统表代替了用户表。我们在其他用户表上也尝试了同样的方法,再次从MTVF中获得了巨大的好处。 执行计划显示,对于更快的查询,TVF上存在聚集索引扫描。 有人能解释一下发生了什么,以及这是否是提高查询性能的可行方法吗


您似乎将执行计划中的“查询成本(相对于批次)”误解为“查询成本(查询运行所需的时间)”。查询的成本与查询的效率或速度关系不大

我在运行此查询(更改日期)时同时执行以下两项:

SET STATISTICS IO ON;
SET STATISTICS TIME ON;
对于标记为“慢”的查询(没有UDF的查询),结果是:

The "slow" one

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 8 ms, elapsed time = 8 ms.

(19305 rows affected)
Table 'sysschobjs'. Scan count 1, logical reads 379, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 62 ms,  elapsed time = 61 ms.
对于您标记为“快速”(UDF)的一个,输出是:

The "fast" one

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 7 ms.

(19305 rows affected)
Table 'sysschobjs'. Scan count 0, logical reads 38610, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#B1BBD6DD'. Scan count 1, logical reads 34, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 266 ms,  elapsed time = 329 ms.
从这些统计数据可以看出,非UDF版本是迄今为止的赢家。非UDF的执行时间快了5倍多,但是,UDF查询的IO是疯狂的(读取超过1000倍)


老实说,多行表值函数往往是性能杀手。在3种类型的函数(内联表值、标量值和多行表值)中,它们可能是最慢的,而as-inline通常更快。我在流言中听说,在SQL Server 2019中,标量函数“更好”,然而,我还没有测试过自己,也没有看到任何真正的证据;只是在对话中。

我发现正好相反,没有udf的查询运行了61毫秒(返回19305行)。udf查询在323ms内运行。这也是我所期望的。多行表值函数通常(很大)影响性能。@Larnu我为两个同时运行的查询添加了执行计划。我们在一个单独的驱动器上安装了tempdb,并在Windows Server 2016标准6.3(Build 14393:)上使用Microsoft SQL Server 2016(SP1)(KB3182545)-13.0.4001.0(X64)……不是标记的2012,而是在不同的2012服务器上使用相同的结果。执行计划并不意味着速度。它们是完全不同的东西。我也有一个“98%”的第一个查询成本,然而,这并没有改变事实,它的速度是原来的5倍。您可以使用
SET STATISTICS time ON获取竞争查询所需的时间。如果您查看times,您可能会发现没有UDF的查询是更好的选择。UDF chocie在IO上也差得多。我查询的IO为非UDF的
扫描计数1,逻辑读取379
,UDF的
扫描计数0,逻辑读取38610
+
扫描计数1,逻辑读取34
。更糟糕的是。(您可以使用
设置统计信息IO打开来查看IO统计信息;
)是的,我就是这么做的。在这种情况下,‘查询成本(相对于批次)’的用途是什么?@cloudsafe上一次我听说它是微软的代言人,“我们没有一个模糊的想法,所以这里有一些数字可能是高度错误的信息。”
The "fast" one

 SQL Server Execution Times:
   CPU time = 0 ms,  elapsed time = 0 ms.
SQL Server parse and compile time: 
   CPU time = 0 ms, elapsed time = 7 ms.

(19305 rows affected)
Table 'sysschobjs'. Scan count 0, logical reads 38610, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table '#B1BBD6DD'. Scan count 1, logical reads 34, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

(1 row affected)

 SQL Server Execution Times:
   CPU time = 266 ms,  elapsed time = 329 ms.