【问题标题】:How to troubleshoot sql server performance problem如何排查sql server性能问题
【发布时间】:2010-08-13 16:25:36
【问题描述】:

好的,这个普遍的问题在过去 6 个月里已经出现了两次丑陋的问题(不同的存储过程)。我们让内部用户在应用程序中报告超时错误。我们可以在受控环境中重现应用程序中的问题。因此,我们通过使用 sp_who2 检查阻塞的正常步骤。一切看起来都很好,没有阻塞。所以我们做一个 sql 跟踪来确切地查看该过程是如何执行的。我们将其复制到 SQL Management Studio 中的新窗口并执行 sql 跟踪告诉我们 ADO.Net 正在执行的操作,并在几毫秒内完成。我们的应用程序超时为 30 秒。当这个问题在几个月前发生时,我们有 SQL Server 2005。我们现在已经升级到 SQL Server 2008 R2。诊断此类问题的下一步是什么?

@Martin:感谢您的回复。我会详细阅读你的帖子,让你知道我发现了什么。在此之前,这是您请求的 SP 中的 sql:

Select 
    @Exists=0, 
    @EarnRecId=0,
    @SuppStatusId = 0,
    @SLRecId = 0,
    @EarnRecDS = Null

Select
    @EarnRecId = er.EarningsId,
    @EarnRecDS = Convert(Varchar(26),er.Datestamp, 109),
    @SuppStatusId = s.SuppStatusId,
    @SLRecId = s.SLId
From
    Tracking tr
    Inner Join Supps s On s.SuppId = tr.SuppId
    Inner Join Earnings er On er.EarnRecId = s.SuppId
Where
    tr.ClaimId = @ClaimId
    and er.FiscalYr = @FiscalYr
    And er.EmplyrId In (@EmpId1,@EmpId2)

If @EarnRecId > 0
    Begin
        Set @Exists=1
    End

【问题讨论】:

  • 索引或统计数据是问题所在。由于某种原因,来自 ADO 的查询计划与直接在服务器上的查询计划不同。因此,请检查您的索引和统计信息。
  • 为什么 ado.net 和 sql management studio 执行完全相同的存储过程会有所不同?要尝试缓解问题,只需更新统计信息和碎片整理索引?
  • @user - 不会有。当然,这两个调用都将使用相同的统计信息和索引,因此如果这是导致问题的原因,则两者都应该发生。几乎可以肯定是参数嗅探。现在不要重建索引/统计信息!这将导致计划从缓存中删除,并阻止任何确认这一点的尝试。你能发布查询吗?
  • 我建议尝试以下方法。 (1) 确定最不常见和最常见的 ClaimId、FiscalYr 和 EmplyrId 值。 (2) 将最不常见的替换为一个版本的选择查询作为常量 (3) 对最常见的执行相同操作。 (4) 比较执行计划。顺便说一句,我有点不确定标量变量的赋值在哪里离开了我的理论。如果您要删除分配,结果是否只能保证返回一行?
  • 不确定您是否意识到这一点,但您可以使用 SQL 分析器查看事件的执行计划。这可以帮助确定问题是否是 Martin 建议的参数嗅探。详情在这里:tinyurl.com/2xccjm

标签: sql-server performance stored-procedures


【解决方案1】:

可能是参数嗅探。

当调用存储过程并且缓存中没有与连接的set 选项匹配的现有执行计划时,将使用在该调用时传入的参数值编译新的执行计划。

当传递的参数不典型(例如具有异常高的选择性)时,有时会发生这种情况,因此生成的计划将不适用于具有不同参数的大多数其他调用。

SSMS 对选项 SET ARITH_ABORT 有不同的默认值,因此当您在 SSMS 中执行存储过程时,不会收到相同的有问题的计划。

下次发生这种情况时,调查该问题的最简单方法可能是使用 2 个单独的 SSMS 窗口,同时启用“包括实际执行计划”选项

SET ARITHABORT OFF
EXEC YourProc ...

在另一个方面

SET ARITHABORT ON
EXEC YourProc ...

假设默认的 ADO.NET 和 SSMS 连接选项第一个应该使用缓存中的错误计划。

如果这对您不起作用,您可以使用 profiler 查看您需要调整哪些其他设置选项来获得错误的计划,或者只使用 profiler 直接获取执行计划 - 或者您可以从 DMV 中检索它们如下。

select p.query_plan, *
from sys.dm_exec_requests r
cross apply sys.dm_exec_query_plan(r.plan_handle) p
where r.session_id = <spid of your ADO.NET connection>

您可能会发现有问题的计划会执行数万次单独的索引搜索,而好的计划会避免这种情况。

【讨论】:

  • 感谢您的帮助。我有一个解决方案,但我不喜欢它。有问题的 SP 连续执行两次。在上述调用期间唯一更改的参数是@FiscalYr。第一个呼叫是 20102011,而下一个呼叫(慢速呼叫)是 20092010。第一个呼叫很快。我终于设置了 CommandTimeout = 0,这样我就可以知道通话需要多长时间,超过 3 分钟。我不明白为什么,因为每种情况下的两个内部连接都返回 1 条记录,所以 qry 计划应该是相同的。如果第一次调用返回 1 条记录,而第二次调用返回 10000 条记录,我可能会理解
  • 无论如何,解决方案是将“重新编译”放在我非常讨厌的 SP 上,因为它更像是一个 hack,而不是一个解决方案。我不喜欢在程序中加入类似的东西或加入提示。哦,顺便说一句,有趣的是,在我增加超时并让两者都运行之后,如果我尝试再次尝试运行它们......两者都很快,直到我执行“dbcc freeproccache”
  • 你可以使用OPTION (OPTIMIZE FOR (@FiscalYr UNKNOWN)) 你能得到慢速调用的实际执行计划吗?如果是这样,那里应该有一些明显的东西。
  • ...我的意思是您可能会发现它所做的工作比您预期的要多得多,并且连接返回的行数明显多于一行。随时在您的问题中发布实际的执行 XML 计划。
【解决方案2】:

马丁完全正确。但我会加上我的 2 美分来总结一下:

  1. 显然,SSMS 和您的应用使用不同的执行计划
  2. 为什么?因为您的应用使用缓存计划和 SSMS,默认情况下会告诉服务器始终创建新计划。
  3. 快速而肮脏的解决方案 - 清除缓存

运行这个

DBCC FREEPROCCACHE

帮助 90% 的时间。

PS。 (海事组织)说,您重新启动了服务器。服务器仍在忙于启动等,但您的 Web 应用程序已经开始从用户那里获取 http 请求!所以你可怜的小 SQL 开始创建和缓存执行计划......同时做很多其他事情!这就是重新启动繁忙的机器后执行计划远非最佳的原因......

【讨论】:

    猜你喜欢
    • 2012-07-25
    • 2016-03-02
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-05
    • 2012-05-30
    相关资源
    最近更新 更多