我编写了一个表值UDF,该值由CTE开始,以从大型表返回行的子集。
CTE中有多个联接。几个内部表和一个左表连接到其他表,这些表不包含很多行。
CTE具有where子句,该子句返回日期范围内的行,以便仅返回所需的行。
然后,我将在4个自左联接中引用此CTE,以便使用不同的标准来建立小计。
该查询非常复杂,但这是其简化的伪版本
WITH DataCTE as
(
SELECT [columns] FROM table
INNER JOIN table2
ON [...]
INNER JOIN table3
ON [...]
LEFT JOIN table3
ON [...]
)
SELECT [aggregates_columns of each subset] FROM DataCTE Main
LEFT JOIN DataCTE BananasSubset
ON [...]
AND Product = 'Bananas'
AND Quality = 100
LEFT JOIN DataCTE DamagedBananasSubset
ON [...]
AND Product = 'Bananas'
AND Quality < 20
LEFT JOIN DataCTE MangosSubset
ON [...]
GROUP BY [
我感到SQL Server感到困惑,并为每个自联接调用CTE,这似乎通过查看执行计划得到了证实,尽管我承认不是阅读这些专家的专家。
我本以为SQL Server足够聪明,只能从CTE执行一次数据检索,而不是执行几次。
我尝试了相同的方法,但没有使用CTE来获取数据的子集,而是使用了与CTE中相同的选择查询,但是将其输出到临时表中。
引用CTE版本的版本需要40秒钟。引用临时表的版本需要1到2秒。
为什么SQL Server不够聪明,无法将CTE结果保存在内存中?
我喜欢CTE,在这种情况下尤其如此,因为我的UDF是表值的,因此它使我可以将所有内容保留在一个语句中。
要使用临时表,我需要编写一个多语句表,其值是UDF,但我发现它的解决方案略逊一筹。
你们中的某些人在CTE中是否遇到过此类性能问题,如果是这样,您如何对它们进行排序?
谢谢,
卡洛斯
最佳答案
我相信每次都能获得CTE结果。使用临时表,结果将被存储直到被删除。这似乎可以解释您切换到临时表时看到的性能提升。
另一个好处是,您可以在临时表上创建索引,而对cte则不能。不知道您的情况是否有好处,但是很高兴知道。
相关阅读:
引用最后一个链接:
The CTE's underlying query will be called each time it is referenced in the immediately following query.
我想说说临时表。不幸的是,优雅并不总是最好的解决方案。
更新:
嗯,这使事情变得更加困难。如果不查看整个环境,我很难说。
一些想法:
left join
,则可以将其移到索引 View 中。如果能够执行此操作,则即使在临时表上,您也可能会看到性能提升。 关于sql-server - 自连接中引用的SQL Server CTE速度很慢,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3054843/