为什么这个CTE表达式在临时表运行正常时挂起

时间:2013-08-10 04:01:45

标签: sql sql-server sql-server-2008 tsql common-table-expression

我有下面的SQL CTE声明,我发现它是性能的瓶颈。在调试时,它只是挂起(我认为它会进行表扫描)所以我用临时表替换它,查询运行正常。我想知道CTE表达式的编写方式是否有所不同,这使得语句挂起。我知道CTE附带了一些性能影响,但我不认为我在下面的查询中做了什么特别的事情让CTE给我这么糟糕的表现。

;with ContList (ContKey, CKey, CreatedDate, DeletedDate, SourceId) AS    
(    
 SELECT ContKey, CKey, CreatedDate, DeletedDate, SourceId FROM #someTempTable    

 UNION ALL    

 SELECT list.ContKey AS ContKey,     
     fact.CKey AS CKey,           
     case when fact.CreatedDate > list.CreatedDate then fact.CreatedDate else list.CreatedDate end AS CreatedDate,    
     case when isnull(fact.DeletedDate, '9999/01/01') < isnull(list.DeletedDate, '9999/01/01') then fact.DeletedDate else list.DeletedDate end AS DeletedDate,                    
     fact.DataSourceDimKey As SourceId                  
 FROM ContList list    
     INNER JOIN SomeFact fact ON list.CKey = fact.DimKey    
     INNER JOIN SomeDimvw someDim on someDim.SomeKey = fact.SomeKey    
     INNER JOIN #contTypes contTypes on someDim.SomeTypeId = contTypes.SomeTypeId      
 WHERE list.DeletedDate IS NULL       
)    

我用以下代码替换了上面的查询:

 SELECT ContKey, CKey, CreatedDate, DeletedDate, SourceId FROM #someTempTable    

 UNION ALL    

 SELECT list.ContKey AS ContKey,     
     fact.CKey AS CKey,           
     case when fact.CreatedDate > list.CreatedDate then fact.CreatedDate else list.CreatedDate end AS CreatedDate,    
     case when isnull(fact.DeletedDate, '9999/01/01') < isnull(list.DeletedDate, '9999/01/01') then fact.DeletedDate else list.DeletedDate end AS DeletedDate,                    
     fact.DataSourceDimKey As SourceId                  
 into #ContList    
 FROM #ContList list    
     INNER JOIN SomeFact fact ON list.CKey = fact.DimKey    
     INNER JOIN SomeDimvw someDim on someDim.SomeKey = fact.SomeKey    
     INNER JOIN #contTypes contTypes on someDim.SomeTypeId = contTypes.SomeTypeId      
 WHERE list.DeletedDate IS NULL       
)    

3 个答案:

答案 0 :(得分:3)

我最近有一个(可能是相关的)情况,使用CTE的复杂查询会产生不一致的结果,具体取决于提供的参数。

例如:

第一次测试:

  1. 重新启动SQL Server
  2. 使用参数A运行查询,在&lt;中获取答案1秒;
  3. 使用参数B运行查询,在&lt;中获取答案1秒;
  4. 第二次测试:

    1. 重新启动SQL Server
    2. 使用参数B运行查询,在64s内获得答案;
    3. 使用参数A运行查询,在64s中获得答案;
    4. 原来,为“A”生成的查询计划是有效的,而为“B”生成的查询计划则不是;由于查询计划是缓存的,因此第一个查询在重新启动服务器控制所有查询的性能后运行。

      解决方案是强制重建数据库的统计信息。

答案 1 :(得分:1)

CTE只是语法。它被执行了。在循环连接中,CTE被执行多次。 #temp已实现,因此只运行一次。

答案 2 :(得分:0)

通过SQL Server MVP Gail Shaw检查此QnA和响应:

http://www.sqlservercentral.com/Forums/Topic415829-338-1.aspx

简而言之, CTE 就像临时视图,当您检查执行计划时,它会内联到查询中。 TempTables 是在tempDB中创建的

表比视图更快(在您的情况下是递归视图)。希望这能解释两种方法之间的性能差异。