0

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

3 回答 3

3

我最近遇到了一个(可能相关的)情况,其中带有 CTE 的复杂查询会给出不一致的结果,具体取决于提供的参数。

例如:

第一次测试:

  1. 重新启动 SQL Server
  2. 带参数A运行查询,<1s得到答案;
  3. 带参数B运行查询,<1s得到答案;

第二次测试:

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

结果表明为“A”生成的查询计划是有效的,而为“B”生成的则不是;由于查询计划被缓存,服务器重新启动后运行的第一个查询控制了所有查询的性能。

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

于 2013-08-10T04:19:22.570 回答
1

A CTE is just syntax. It is executed. In a loop join the CTE is executed multiple times. A #temp is materialized so it is run just once.

于 2013-08-10T10:13:46.197 回答
0

Check this QnA and response by SQL Server MVP Gail Shaw:

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

In short it says CTEs are like temporary views and when you check the execution plan it is inlined into query. TempTables are tables created in tempDB.

Tables are faster than views (In your case a recursive view). Hopefully that explains the performance difference between two approaches.

于 2013-08-11T19:43:15.573 回答