Tsql 在本例中,为什么CTE的性能比临时表差

Tsql 在本例中,为什么CTE的性能比临时表差,tsql,common-table-expression,Tsql,Common Table Expression,我最近问了一个关于CTE的问题,并使用了没有真正根记录的数据(即,不是根记录有一个空的父\u Id,而是它自己的父) 问题链接在这里 这个问题的答案已经提供,我现在有了我需要的数据,但是我对我认为对我来说两种方法之间的差异感兴趣 生成所需数据的方法是创建一个包含清理过的父数据的临时表,然后对其运行递归CTE。这看起来像下面 Select CASE WHEN Parent_Id = Party_Id THEN NULL ELSE Parent_Id END AS Act_Paren

我最近问了一个关于CTE的问题,并使用了没有真正根记录的数据(即,不是根记录有一个空的父\u Id,而是它自己的父)

问题链接在这里

这个问题的答案已经提供,我现在有了我需要的数据,但是我对我认为对我来说两种方法之间的差异感兴趣

生成所需数据的方法是创建一个包含清理过的父数据的临时表,然后对其运行递归CTE。这看起来像下面

Select CASE
    WHEN Parent_Id = Party_Id THEN NULL
    ELSE Parent_Id
END AS Act_Parent_Id
, Party_Id
, PARTY_CODE
, PARTY_NAME
INTO #Parties
FROM DIMENSION_PARTIES
WHERE CURRENT_RECORD = 1),

WITH linkedParties
AS
(
Select Act_Parent_Id, Party_Id, PARTY_CODE, PARTY_NAME, 0 AS LEVEL
FROM #Parties
WHERE Act_Parent_Id IS NULL

UNION ALL

Select p.Act_Parent_Id, p.Party_Id, p.PARTY_CODE, p.PARTY_NAME, Level + 1
FROM #Parties p
inner join
linkedParties t on p.Act_Parent_Id = t.Party_Id
)

Select *
FROM linkedParties
Order By Level
我还试图通过定义两个CTE来检索相同的数据。一个用于模拟上面临时表的创建,另一个用于执行相同的递归工作,但引用初始CTE而不是临时表

WITH Parties
AS
(Select CASE
    WHEN Parent_Id = Party_Id THEN NULL
    ELSE Parent_Id
END AS Act_Parent_Id
, Party_Id
, PARTY_CODE
, PARTY_NAME
FROM DIMENSION_PARTIES
WHERE CURRENT_RECORD = 1),

linkedParties
AS
(
Select Act_Parent_Id, Party_Id, PARTY_CODE, PARTY_NAME, 0 AS LEVEL
FROM Parties
WHERE Act_Parent_Id IS NULL

UNION ALL

Select p.Act_Parent_Id, p.Party_Id, p.PARTY_CODE, p.PARTY_NAME, Level + 1
FROM Parties p
inner join
linkedParties t on p.Act_Parent_Id = t.Party_Id
)

Select *
FROM linkedParties
Order By Level
现在这两个脚本在同一台服务器上运行,但是临时表方法在大约15秒钟内产生结果

多重CTE方法需要5分钟以上的时间(事实上,我从未等待结果返回)

为什么临时表方法会更快

我认为这与记录计数有关。基表中有200k条记录,从内存来看,在处理大型数据集时,CTE性能会严重下降,但我似乎无法证明这一点,所以我想我会与专家核实一下


非常感谢

对于这一点似乎没有明确的答案。对该主题的泛型进行的一些进一步研究提出了许多具有类似问题的其他线索

这一条似乎涵盖了临时表格和CTE之间的许多变化,因此对于希望了解他们的问题的人来说是最有用的


在我的情况下,我的CTE中的大量数据似乎会导致问题,因为它没有缓存在任何地方,因此每次以后引用时重新创建它都会产生很大的影响。

这可能与您遇到的问题不完全相同,但几天前我遇到了一个类似的查询,查询甚至没有处理那么多记录(几千条记录)

昨天我的同事也有类似的问题

为了清楚起见,我们使用的是SQLServer2008R2

我发现的模式似乎使SQLServer优化器偏离了轨道,它在CTE中使用临时表,这些临时表与主select语句中的其他临时表连接在一起

在我的例子中,我最终创建了一个额外的临时表

这是一个样本

我最终做了这样的事:

SELECT DISTINCT st.field1, st.field2
  into #Temp1
FROM SomeTable st
WHERE st.field3 <> 0

select x.field1,  x.field2
FROM #Temp1 x inner join #Temp2 o 
    on x.field1 = o.field1
order by 1, 2
选择不同的st.field1、st.field2
进入#Temp1
从圣
圣菲尔德30号在哪里
选择x.field1、x.field2
从#节奏1 x内部连接#节奏2
在x.field1=o.field1上
按1、2顺序订购
我尝试了下面的查询,但是如果你相信的话,它的速度要慢得多

with temp1 as (
 DISTINCT st.field1, st.field2
    FROM SomeTable st
    WHERE st.field3 <> 0
)
select x.field1,  x.field2
FROM temp1 x inner join #Temp2 o 
    on x.field1 = o.field1
order by 1, 2
使用temp1作为(
不同的圣菲尔德1号、圣菲尔德2号
从圣
圣菲尔德30号在哪里
)
选择x.field1、x.field2
从temp1 x内部连接#Temp2 o
在x.field1=o.field1上
按1、2顺序订购
我还尝试在第二个查询中内联第一个查询,但性能相同,即非常差


SQL Server从未停止让我惊讶。偶尔我会遇到类似这样的问题,这提醒我它毕竟是微软的产品,但最终你可以说其他数据库系统也有自己的怪癖。

CTE只是语法——它是经过评估的。临时工被具体化。这是有据可查的。