代码之家  ›  专栏  ›  技术社区  ›  developer

链式CTE对Temp表的性能影响

  •  2
  • developer  · 技术社区  · 7 年前

    ;WITH CTE1
    AS(    
        SELECT * FROM TableA
    ),
    CTE2
    AS(
        SELECT * FROM TableB b INNER JOIN CTE1 c ON b.id = c.id
    )
    
    SELECT * FROM CTE2
    

    如果我断开CTE链并将CTE1的数据存储到temp表中,那么整个查询的性能就会提高(从1分20秒提高到8秒)。

    ;WITH CTE1
    AS(    
        SELECT * FROM TableA
    )
    
    SELECT * INTO #Temp FROM CTE1
    
    ;WITH CTE2
    AS(
        SELECT * FROM TableB b INNER JOIN #Temp c ON b.id = c.id
    )
    
    SELECT * FROM CTE2
    DROP TABLE #Temp
    

    打破CTE椅子应该提高性能吗?

    SQL Server版本:2008 R2

    3 回复  |  直到 6 年前
        1
  •  4
  •   Gordon Linoff    7 年前

    显然,它可以,正如你自己所展示的。

    为什么?最明显的原因是优化器知道临时表的大小。这为优化查询提供了更多信息。CTE只是一个估计。因此,您看到的改进是由于查询计划。

    有时,您故意将cte具体化为临时表,以便向它们添加索引。这也可以提高性能。

        2
  •  2
  •   paparazzo    7 年前

    考虑CTE1是昂贵的

    ;WITH CTE1
    AS(    
        SELECT * FROM TableA
    )
    
    SELECT * INTO #Temp FROM CTE1
    

    以上保证cte1只运行一次。

    即使使用了临时参数,也应该考虑索引/PK并对插入进行排序。

        3
  •  2
  •   Pittsburgh DBA    7 年前

    这取决于许多因素。如果可以的话,尽量写一句话。过早的优化是很多罪恶的根源。

    如果确实遇到性能问题,则分解单个语句有以下几点好处:

    • 它可以通过降低复杂性来提高可维护性,这是许多非功能性需求之一。
    • 只要中间物化的成本和节省的时间小于原成本,就可以得到更好的方案。
    • 中间表可以被索引。
    • 您可以选择将优化器提示(例如MAXDOP)应用于select语句,而不是一个巨大的语句。当您需要操纵内存授予时,这尤其有用。
    • 您可以调整单个语句以消除对tempdb的溢出。
    推荐文章