繁体   English   中英

链式 CTE 与 Temp 表的性能影响

[英]Performance impact of chained CTE vs Temp table

我有以下链式 CTE 查询(简化):

;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 的数据存储到临时表中,那么整体查询的性能会提高(从 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

CTE1 和 CTE2 中有复杂的查询。 我刚刚创建了一个简化版本来解释这里。

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

SQL Server 版本:2008 R2

显然,它可以,正如您自己所展示的那样。

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

另一个原因是 CTE 在查询中被多次引用。 SQL Server 不会实现 CTE,因此定义代码将运行多次。

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

尽管如此,我更愿意避免使用临时表。 优化器通常非常好。

考虑 cte1 很贵

;WITH CTE1
AS(    
    SELECT * FROM TableA
)

SELECT * INTO #Temp FROM CTE1

以上保证 cte1 只运行一次。

链接的 cte 可以多次评估 cte1。

即使使用#temp,您也应该考虑索引/PK 并对插入进行排序。

这取决于许多因素。 如果可以,请始终尝试编写单个语句。 过早的优化是许多罪恶的根源。

如果您确实遇到了性能问题,以下是分解单个语句的一些优势:

  • 它可以通过降低复杂性来提高可维护性,这是许多非功能性需求之一。
  • 只要中间物化的成本和节省的时间小于原始成本,它就可以产生更好的计划。
  • 中间表可以被索引。
  • 索引、主键和唯一约束对优化器非常有帮助,不仅可以用于选择连接类型,还可以用于估计基数,这对内存授予有很大影响。
  • 您可以选择应用优化器提示,例如 MAXDOP 仅用于选择语句,而不是一个巨大的语句。 当您需要操作内存授权时,这尤其有用。
  • 您可以调整单个语句以消除对 tempdb 的溢出。
  • 根据流程的复杂性和总执行时间,您可以提前释放资源锁,这也取决于您的语句在哪个隔离级别下运行。
  • 如果您的查询计划很差,由于优化器超时,使用不太复杂的单个语句可能会产生更好的整体结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM