SQL Server 2008 R2中的空间会降低性能

问题描述:

我遇到了一个相当奇怪的问题。我在SQL Server中创建了以下查询SQL Server 2008 R2中的空间会降低性能

SELECT * FROM leads.BatchDetails T1 
INNER JOIN leads.BatchHeader h ON T1.LeadBatchHeaderId = h.ID 
WHERE 
T1.LeadBatchHeaderId = 34 
    AND (T1.TypeRC = 'R' OR h.DefaultTypeRC = 'R')  
AND EXISTS (SELECT ID FROM leads.BatchDetails T2 where 
      T1.FirstName = T2.FirstName AND 
      T1.LastName = T2.LastName AND 
      T1.Address1 = T2.Address1 AND 
      T1.City = T2.City AND      
      T1.[State] = T2.[State] AND      
      T1.Zip5 = T2.Zip5 AND      
      T1.LeadBatchHeaderId = T2.LeadBatchHeaderId 
      and t2.ID < t1.ID 
      AND (T2.TypeRC = 'R' OR h.DefaultTypeRC = 'R') 
    ) 

它在2秒内运行得非常快。在格式化代码时,我无意中在AND + EXISTS之间增加了一个额外的SPACE,所以查询看起来像这样。

SELECT * FROM leads.BatchDetails T1 
INNER JOIN leads.BatchHeader h ON T1.LeadBatchHeaderId = h.ID 
WHERE 
T1.LeadBatchHeaderId = 34 
    AND (T1.TypeRC = 'R' OR h.DefaultTypeRC = 'R')  
AND EXISTS (SELECT ID FROM leads.BatchDetails T2 where 
      T1.FirstName = T2.FirstName AND 
      T1.LastName = T2.LastName AND 
      T1.Address1 = T2.Address1 AND 
      T1.City = T2.City AND      
      T1.[State] = T2.[State] AND      
      T1.Zip5 = T2.Zip5 AND      
      T1.LeadBatchHeaderId = T2.LeadBatchHeaderId 
      and t2.ID < t1.ID 
      AND (T2.TypeRC = 'R' OR h.DefaultTypeRC = 'R') 
    ) 

突然间,查询需要13秒来执行。 我在独立的沙箱环境中运行SQL Server,我甚至在不同的沙箱上测试过它。我还在profiler中检查了执行的查询,读取的结果基本相同,但CPU时间有所增加

如果这并不奇怪,它会变得越来越诡异。当我在查询顶部将SELECT * FROM更改为SELECT Field1, ... FROM时,执行时间超过3分钟。

我一直在使用SQL Server 10年,从未见过这样的事情。

编辑: 按照下面的建议看起来,查询是“白色空间敏感的”。但我仍然不知道为什么SELECT * FROMSELECT Field1, ... FROM

我猜你处理两种不同的缓存查询计划:

  • 你,你跑了一次查询,具有一定的参数设置。为了查询计划的目的,SQL Server确定了一个合适的查询计划,并存储了该查询计划“自动参数化”,换句话说,用您为变量提供的值进行替换。
  • 然后,您再次运行相同的查询,并使用不同的参数。该查询得到自动参数化,并匹配现有的缓存查询计划(即使该查询计划对于提供的新参数可能不是最优的!)。
  • 然后,再次运行第二个查询,并留出额外的空间。这一次,自动参数化查询不匹配缓存中的任何内容,因此根据这组参数获取自己的计划(请记住,第一个计划是针对不同的参数集)。这个查询计划恰好结束得更快(或更慢)。

如果这是真正的解释,你应该能够使效果消失,通过运行DBCC FREEPROCCACHE:在自动参数http://msdn.microsoft.com/en-us/library/ms174283.aspx

有很多东西在那里,我个人也很喜欢盖尔肖氏系列:

http://sqlinthewild.co.za/index.php/2007/11/27/parameter-sniffing/ http://sqlinthewild.co.za/index.php/2008/02/25/parameter-sniffing-pt-2/ http://sqlinthewild.co.za/index.php/2008/05/22/parameter-sniffing-pt-3/

(备案,我不知道是否SQL Server的eliminat es /在存储自动参数化查询计划之前对空白进行规范化;我会这样认为的,但是这整个答案都认为它不会!)

+0

我跑的查询总是完全一样对于空白 – Andre 2011-06-15 21:31:33

+0

,查询的两个版本中的一个不可能由某个其他人或代码执行,并且参数不同? 'DBCC FREEPROCCACHE'后你有没有试过重新运行你的测试? – Tao 2011-06-15 21:36:23

快得多这可能与缓存问题有关。当你改变你的查询时,即使只有一个空间,你以前的查询的缓存执行计划将不再使用。如果我的答案是正确的,你应该看到相同(2秒)的性能,当你运行的底部查询第二次...
只是我的2美分

你可以用下面的两个语句清空缓存:

DBCC FreeProcCache 
DBCC DROPCLEANBUFFERS 
+0

我可以证实这一点,但似乎过了一段时间后,空白区可能会或可能不会有所作为。有时它执行的速度非常快,但有时并非如此。非常奇怪的行为。 – Andre 2011-06-15 21:16:35

+0

[本文](http://sqlperformance.com/2014/11/t-sql-queries/multiple-plans-identical-query)证实了你的意思, – 2016-06-08 09:45:21