我有一个复杂的查询,我需要在后续查询中使用(实际更新语句)。我尝试过使用CTE和临时表。使用CTE的性能与临时表方法相比非常糟糕。它像15秒对毫秒。为了简化测试而不是在后续查询中加入CTE / Temp表,我只是从中选择了*。在那种情况下,他们执行相同的操作。
我已经查看了两种方法的执行计划,这两种方法都使用后续查询中的连接,然后只需选择*。与简单选择查询计划大致相同,但在后续选择连接时查询计划不是。具体来说,用于创建和填充临时表的查询计划部分保持不变,而用于创建和填充CTE的查询计划部分随后在具有连接的查询中使用时会发生显着变化。
我的问题是为什么CTE的创建和填充的查询计划会根据临时表的后续使用方式而改变。同样在什么情况下,CTE会产生比临时表更好的性能?
*注意我也使用了表变量,它与临时表方法相当。
由于
答案 0 :(得分:13)
CTE
只是查询的别名。
每次使用它都可能(或可能不会)重新运行。
在CTE
(例如Oracle的SQL Server
)中强制/*+ MATERIALIZE */
实现没有干净的方法,你必须做这样的诡计:
CTE
,HASH JOIN
等)中使用,则 MERGE JOIN
可以提高效果。
在这些场景中,哈希表将直接从CTE
构建,而使用临时表将需要评估CTE
,将结果拉入临时表并读取临时表试。
答案 1 :(得分:9)
你问的是一个复杂的问题,所以你得到了一个复杂的答案:这取决于你。 (我讨厌那个回应)。
但是,严重的是,它与优化程序如何选择数据计划(您已经知道)有关;临时表或变量类似于永久结构,因为执行计划将首先执行与填充该结构相关联的操作,然后在后续操作中使用该结构。 CTE不是临时表; CTE的使用在后续操作使用之前不会计算,因此使用会影响计划的优化方式。
CTE是针对可重用性和维护问题而实施的,不一定是性能;然而,在许多情况下(如递归),它们的表现将优于传统的编码方法。
答案 2 :(得分:2)
我发现通常重复的CTE没有性能改善。
因此,例如,如果您使用CTE填充表,然后使用相同的CTE在以后的查询中加入,则没有任何好处。不幸的是,CTE不是快照,它们必须重复用于两个单独的语句中,因此它们往往被评估两次。
我经常使用内联TVF(可能包含CTE)而不是CTE,它允许正确的重复使用,并且不比我的SP中的CTE更好或更差。
此外,我还发现,如果第一步改变统计数据,执行计划可能会很糟糕,因为第二步的执行计划总是不准确,因为在运行任何步骤之前对其进行评估。
在这种情况下,我看一下手动存储中间结果,确保它们被正确编入索引并将流程拆分为多个SP并添加WITH RECOMPILE以确保后来的SP具有对其实际数据有利的计划要继续经营。
答案 3 :(得分:1)
我尝试使用从大表中过滤的简单选择创建CTE 然后3次取消它。
之后对临时表做同样的事情。
结果是CTE耗时70% - 临时表耗时30%。 因此临时表对于该解决方案更好。
我不认为CTE只使用选定的查询创建临时表,但是3次选择一个大表。