2009-10-07 71 views
12

我有一个复杂的查询,需要在后续查询(实际更新语句)中使用。我已经尝试使用CTE和临时表。使用CTE的性能与临时表方法相比是非常糟糕的。它的东西像15秒比毫秒。为了简化测试,而不是在随后的查询中加入CTE/Temp表,我只需从中选择*。在这种情况下,他们表现相同。SQL 2005 CTE vs TEMP表在其他表的连接中使用时的性能

我已经看过这两种方法的执行计划,并在随后的查询中加入连接,然后简单地选择*。通过简单的选择查询计划大致相同,但随后的选择查询计划不是。具体来说,用于创建和填充临时表的查询计划部分保持不变,而用于创建和填充CTE的查询计划部分随后在具有连接的查询中使用时发生显着变化。

我的问题是,为什么CTE的创建和填充的查询计划随后如何使用,而临时表不是这样。同样在什么情况下,CTE会比临时表产生更好的性能?

*注意我也使用了表变量,它与临时表方法相当。

感谢

回答

9

你在问一个复杂的问题,所以你会得到一个复杂的答案:这取决于。 (我讨厌那个回应)。

然而,严重的是,它与优化器如何选择数据计划(您已经知道)有关;临时表或变量就像一个永久性结构,因为执行计划将执行与首先填充该结构相关的操作,然后在随后的操作中使用该结构。 CTE不是临时表; CTE的使用只有在后续操作使用时才会被计算出来,因此使用会影响计划的优化方式。

CTE的实施可重用性和维护问题,不一定表现;然而,在许多情况下(如递归),它们将比传统的编码方法更好。

13

CTE只是用于查询的别名。

它可能(或可能不)在每次使用时重新运行。

有没有干净的方式来强制SQL ServerCTE物化(如Oracle的/*+ MATERIALIZE */),而你所要做的肮脏把戏是这样的:如果使用

CTE可以提高性能在只需要一次评估的计划中(如HASH JOIN,MERGE JOIN等)。

在这些情况下,散列表将从CTE构建,而使用临时表则需要评估CTE,将结果拖入临时表并再次读取临时表。

+1

是的物化!定义中的PK/IX可能很好。 – crokusek 2013-03-08 17:56:39

2

我发现通常重复的CTE没有得到性能改进。

因此,例如,如果您使用CTE填充表格,然后在稍后的查询中加入相同的CTE,则没有任何好处。不幸的是,CTE不是快照,而且它们必须重复使用以用于两个单独的语句,因此它们倾向于被评估两次。

而不是CTE,我经常使用内联TVF(可能包含CTE),它允许正确的重用,并且没有比我的SP中的CTE更好或更差。

此外,我还发现,如果第一步更改统计信息,使得第二步的执行计划总是不准确,因为它在任何步骤运行之前进行评估,那么执行计划可能会很糟糕。

在这种情况下,我看手动存储中间结果,确保它们正确编制索引,并将进程拆分为多个SP并添加WITH RECOMPILE以确保后面的SP具有对他们所用数据有利的计划实际上将运作。

0

我试图创建CTE与简单的选择与过滤器从大表 然后3次subqueried它。

之后,对临时表做同样的事情。

结果是70%的时间消耗CTE -30%的时间消耗临时表。 所以临时表对于那些解决方案更好。

我不认为CTE只使用选定的查询生成临时表,但是3次选择一个大表。