【问题标题】:Space in SQL Server 2008 R2 slows down performanceSQL Server 2008 R2 中的空间会降低性能
【发布时间】:2011-09-15 21:04:15
【问题描述】:

我遇到了一个相当奇怪的问题。我在 SQL Server 中创建了以下查询

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,我什至在不同的沙箱上对其进行了测试。我还在分析器中检查了执行的查询,读取几乎相同,但 CPU 时间增加了

如果这还不够奇怪,那就越来越奇怪了。当我在查询顶部将 SELECT * FROM 更改为 SELECT Field1, ... FROM 时,执行需要 3 分钟以上。

我已经使用 SQL Server 10 年了,从来没有见过这样的事情。

编辑: 在遵循以下建议后,查询似乎是“空白敏感的”。但是我仍然不知道为什么SELECT * FROMSELECT Field1, ... FROM 快很多

【问题讨论】:

    标签: sql-server performance


    【解决方案1】:

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

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

    如果这确实是解释,您应该能够通过运行 DBCC FREEPROCCACHE: http://msdn.microsoft.com/en-us/library/ms174283.aspx 来消除效果

    那里有很多关于自动参数化的东西,我个人喜欢 Gail Shaw 的系列:

    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 是否在存储自动参数化查询计划之前消除/规范化空格;我会假设是这样,但整个答案假设它没有!)

    【讨论】:

    • 我运行的查询总是完全相同,除了空格
    • 两个版本的查询之一不可能由其他人或某处的代码使用不同的参数执行?您是否尝试在 DBCC FREEPROCCACHE 之后重新运行测试?
    【解决方案2】:

    这很可能与缓存问题有关。当您更改查询时,即使只更改一个空格,也将不再使用先前查询的缓存执行计划。如果我的回答是正确的,那么当您第二次运行底部查询时,您应该会看到相同的(2 秒)性能...
    只是我的 2 美分

    您可以使用以下两条语句刷新缓存:

    DBCC FreeProcCache
    DBCC DROPCLEANBUFFERS
    

    【讨论】:

    • 我可以确认这一点,但似乎过了一段时间,空白可能会或可能不会有所作为。有时它执行得非常快,有时却没有。非常奇怪的行为。
    • This article 证实了你所说的,
    猜你喜欢
    • 1970-01-01
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多