缓存中间 CTE 以供多种用途

Luí*_*ade 4 sql-server cte

我正在处理这个我选择使用 CTE 的巨大查询。由于此查询的复杂性,我最终不得不在后续查询中多次重用中间查询结果。我面临的问题可以通过以下玩具代码进行总结:

WITH cte1 AS (
    SELECT id, name
    FROM Manager)
, cte2 AS (
    SELECT id, name
    FROM Employee 
    LEFT OUTER JOIN cte1 ON Employee.id = cte1.id)
SELECT *
FROM cte1
Run Code Online (Sandbox Code Playgroud)

我注意到在一个相当小的表中寻找异常数量的索引,该表在第一个查询中被查询,根据执行计划,占整个查询的大约 30%。这让我相信基表被多次查询,因为它在后续查询中被多次引用。

我的印象是 CTE 中的中间结果被缓存,直到最后的语句。阅读微软关于 CTE 的文档,我找不到任何理由不这么想。

中间 CTE 是否缓存用于WITH语句中的多种用途?如果没有,有没有办法在不重写查询的情况下缓存它?

谢谢!

Aar*_*and 9

不,没有办法缓存 CTE;如果它被多次引用,它通常会被执行多次。如果您想避免这种情况,您可以使用 #temp 表来缓存结果。

在某些情况下,执行计划可能足够简单,以至于 CTE 只实现一次(这在技术上并不意味着它被“缓存”了),或者结果可以与假脱机一起重用。我手头没有任何例子,即使我有,你也不能依赖它总是如此。甚至像这样简单的事情:

CREATE TABLE dbo.OneTuple(id int PRIMARY KEY);
INSERT dbo.OneTuple(id) VALUES(1);
GO

;WITH cte AS 
(
  SELECT id FROM dbo.OneTuple
)
SELECT id FROM cte
UNION ALL
SELECT id FROM cte;
Run Code Online (Sandbox Code Playgroud)

产生两个相同的索引扫描:

在此处输入图片说明

另请参阅Stack Overflow 上的这个很棒的 Martin Smith 答案,并在此反馈项目中进行了讨论。