Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sql-server-2005/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 表值函数破坏我的查询性能_Sql Server_Sql Server 2005_Sql Server 2008 - Fatal编程技术网

Sql server 表值函数破坏我的查询性能

Sql server 表值函数破坏我的查询性能,sql-server,sql-server-2005,sql-server-2008,Sql Server,Sql Server 2005,Sql Server 2008,我今天在尝试以我期望的方式执行查询时,经历了一段可怕的时光。昨天我不得不对查询中的一个表值函数做一点小小的更改,这一更改对查询的性能产生了巨大的影响。在评估执行计划并查看统计信息IO和时间后,我发现,由于我更改了函数以返回一个表变量,而不仅仅是一个结果集,因此它正在对一个被查询的表进行完全扫描 我的问题是,为什么让它返回表(TableVariable),而不仅仅是一个选择/结果集会导致计划发生如此大的变化 难解的….返回一个表变量将使其成为一个多语句表值函数,并且可能会对性能造成不利影响,因为它

我今天在尝试以我期望的方式执行查询时,经历了一段可怕的时光。昨天我不得不对查询中的一个表值函数做一点小小的更改,这一更改对查询的性能产生了巨大的影响。在评估执行计划并查看统计信息IO和时间后,我发现,由于我更改了函数以返回一个表变量,而不仅仅是一个结果集,因此它正在对一个被查询的表进行完全扫描

我的问题是,为什么让它返回表(TableVariable),而不仅仅是一个选择/结果集会导致计划发生如此大的变化


难解的….

返回一个表变量将使其成为一个多语句表值函数,并且可能会对性能造成不利影响,因为它被视为一个表,除非SQL Server没有可用的统计数据来作为一个好的执行计划的基础-因此它将函数估计为返回一个非常小的值行数。如果它返回更多的行,那么生成的计划可能会比最优的少很多

然而,只返回一个SELECT会使它成为一个内联表值函数——请将它更多地看作一个视图。在这种情况下,实际的底层表会被带入主查询,并且可以基于适当的统计信息生成更好的执行计划。您会注意到,在本例中,执行计划根本不会提到函数,因为它基本上只是将函数合并到主查询中

CSS SQL Server工程师在其上提供了大量参考资料,包括(引用):

但如果你使用多语句TVF, 它被当作另一个一样对待 桌子因为没有 统计数据可用,SQL Server已 作出一些假设,并 一般提供较低的估计。如果你的 TVF只返回几行,它将 没事。但是如果你想 在TVF中填充数千个 行,如果此TVF与 其他表格,效率低下的计划可以 低基数估计的结果


如果没有更多的信息,真的不可能给出确切的答案。然而,因为我喜欢在黑暗中疯狂的刺


表变量不能由引擎优化——引擎在生成执行计划时总是“假定”表变量中只有一行。这就是您可能会看到奇怪性能的原因之一。

这是因为多语句表值UDF不能与它所使用的SQL语句的其余部分内联处理,因此不能成为语句缓存计划的一部分。。这意味着,对于查询生成的最终结果集中的每一行,,它必须与它所使用的SQL的其余部分分开编译


内联表值UDF otoh与它所用的sql一起被处理和编译,因此它成为缓存计划的一部分,并且只被处理和编译一次,而不管生成多少行

当使用多语句表值UDF时,该UDF在调用者可以使用其结果之前一直运行到完成。使用内联表值的UDF,SQL Server基本上将UDF扩展到调用查询中,就像宏扩展一样。除其他外,这具有以下影响:

  • 调用查询的
    WHERE
    子句可以直接插入到内联表值的UDF中,但不能插入到多语句UDF中。因此,如果表值UDF生成了许多行,这些行将被调用查询的
    WHERE
    子句过滤掉,那么查询优化器可以将
    WHERE
    子句直接应用到内联表值UDF中,而不是应用到多语句UDF中
  • 如果SQL Server有这样的概念,则内联表值UDF的行为类似于参数化的
    视图
    ,而多语句表值UDF的行为类似于在查询中填充并使用表变量

如果您的UDF返回许多行并由一个表支持,我想这可能就是表扫描的来源。要么向UDF中添加更多参数以使调用者能够约束其结果大小,要么在朋友的帮助下尝试将其重新格式化为内联表值UDF,如
UNION
等。我会不惜一切代价避免多语句表值UDF,除非已知结果大小只有几行,并且很难生成使用基于集合的逻辑获得所需结果。

在SQL Server 2014上,我们能够通过将表值函数数据插入临时表,然后对其执行联接来解决问题。而不是直接连接到表值函数

这将我们的执行时间从2分钟提高到4秒

以下是一个对我们团队有效的示例:

--慢速查询(2分钟):

--快速查询(4秒):


添加了一段引用CSS参考文章的话,这篇文章解释得比我好:)我不同意否决票。我曾在一次会议上看到Kimberly Tripp对此做了演示,使用了一个非常简单的UDF,根本不涉及任何表格(因此统计数据将是irelevant)。udf所做的只是基于每行中的另一列使用一些简单表达式转换输入参数。一个udf是标准表值udf,另一个是内联udf。SQL生成了几百万行(表中每行一行)。内联自定义项在不到一秒钟的时间内处理完毕。标准udf花了几分钟时间。@charles Bretana是的,但您所说的是从内联标量udf到表值udf。而OP已经从内联表值函数变成了多语句表值UDF。因此,在这种情况下,我的答案是正确的,而否决票则不是justified@AdaTheDev,在这个有限的基础上,我将取消否决票,但也许你错过了p
DECLARE @id INT = 1;

SELECT * 
FROM [data].[someTable] T
INNER JOIN [data].[tableValueFunction](@id) TVF ON TVF.id = T.id;
DECLARE @id INT = 1;

SELECT * 
INTO #tableValueFunction
FROM [data].[tableValueFunction](@id) TVF

SELECT * 
FROM [data].[someTable] T
INNER JOIN #tableValueFunction TVF ON TVF.id = T.id;