繁体   English   中英

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

[英]Why this CTE expression hangs while temp table runs fine

我在下面的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       
)    

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

例如:

第一次测试:

  1. 重新启动SQL Server
  2. 使用参数A运行查询,在1秒内得到答案;
  3. 使用参数B运行查询,在1秒内得到答案;

第二次测试:

  1. 重新启动SQL Server
  2. 使用参数B运行查询,在64s内获得答案;
  3. 使用参数A运行查询,在64 s内得到答案;

原来,为“ A”生成的查询计划是有效的,而为“ B”生成的查询计划则没有效率。 由于查询计划已缓存,因此第一个查询在服务器重新启动后运行,这将控制所有查询的性能。

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

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

检查此QnA并通过SQL Server MVP Gail Shaw进行响应:

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

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

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

暂无
暂无

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

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