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

时间:2014-10-27 12:10:07

标签: tsql common-table-expression

我最近问了一个关于CTE和使用没有真正根记录的数据的问题(即代替具有NULL parent_Id的根记录,它本身就是父级)

问题链接在这里; Creating a recursive CTE with no rootrecord

答案已经提供给了这个问题,我现在掌握了我需要的数据,但是我对我认为可以使用的两种方法之间的区别感兴趣。

产生我需要的数据的方法是创建一个临时表,其中清理了父数据,然后运行递归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性能严重下降,但我似乎无法证明我认为我会向专家查询。

非常感谢

2 个答案:

答案 0 :(得分:0)

因为似乎没有明确的答案,对该主题的泛型的进一步研究引发了许多具有类似问题的其他线索。

这个似乎涵盖了临时表和CTE之间的许多变化,因此对于那些希望阅读其问题的人来说非常有用;

Which are more performant, CTE or temporary tables?

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

答案 1 :(得分:0)

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

昨天我的同事遇到了类似的问题。

要明确我们正在使用SQL Server 2008 R2。

我发现并且似乎将sql server优化器抛出轨道的模式是在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

我尝试了以下查询,但如果你能相信的话,那么很多就会慢一点。

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

我还尝试在第二个查询中内联第一个查询,性能相同,即非常糟糕。

SQL Server永远不会让我感到惊讶。偶尔我会遇到像这样的问题,这些问题让我想起它毕竟是微软产品,但最后你可以说其他数据库系统都有自己的怪癖。