【问题标题】:Why is performance of CTE worse than temporary table in this example为什么在这个例子中 CTE 的性能比临时表差
【发布时间】:2015-03-18 04:02:57
【问题描述】:

我最近问了一个关于 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 分钟以上(事实上,我从来没有等到结果返回)。

临时表方法会更快吗?

我认为它的价值与记录数有关。基表中有 20 万条记录,在处理大型数据集时,内存 CTE 性能严重下降,但我似乎无法证明这一点,所以我想咨询专家。

非常感谢

【问题讨论】:

  • CTE 只是语法 - 它被评估。 #temp 已实现。这是有据可查的。

标签: tsql common-table-expression


【解决方案1】:

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

这似乎涵盖了临时表和 CTE 之间的许多变化,因此对于希望阅读他们的问题的人最有用;

Which are more performant, CTE or temporary tables?

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

【讨论】:

    【解决方案2】:

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

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

    需要说明的是,我们使用的是 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 总是让我惊叹不已。偶尔我会遇到类似这样的问题,这让我想起它毕竟是微软的产品,但最后你可以说其他数据库系统有自己的怪癖。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-25
      • 2010-10-15
      • 2013-05-21
      相关资源
      最近更新 更多