【问题标题】:Stored procedure performance randomly plummets; trivial ALTER fixes it. Why?存储过程性能随机下降;琐碎的 ALTER 修复它。为什么?
【发布时间】:2009-12-04 22:49:52
【问题描述】:

我注意到在 SQL Server 2005 上有几个存储过程,当从我的 ASP.NET MVC 应用程序调用时突然需要很长时间才能完成,该应用程序在四台服务器的 IIS6 网络场中运行。正常,预期执行时间小于一秒;意外异常执行时间为 25-45 秒。这个问题似乎永远不会自行纠正。

但是,如果我 ALTER 存储过程(即使我没有更改过程中的任何内容,除了可能在 SSMS Modify 命令创建的脚本中添加一个空格),完成时间将恢复为预期的完成时间。

IIS 和 SQL Server 在不同的机器上运行,两者都运行 Windows Server 2003 R2 Enterprise Edition。 SQL Server 是标准版。所有机器都有双 Xeon E5450 3GHz CPU 和 4GB RAM。 SQL Server 是通过千兆以太网使用其 TCP/IP 协议访问的(不确定是什么物理介质)。

网络场中的所有网络服务器都存在问题。当我从开发机器上的 SSMS 中的查询窗口调用该过程时,该过程在正常时间内完成。这很奇怪,因为我的印象是 SSMS 使用与 .NET 中相同的 SqlClient 驱动程序。当我将 Web 应用程序的开发实例指向生产数据库时,我再次得到异常长的完成时间。如果我的 SqlCommand Timeout 太短,我会得到 ​​p>

System.Data.SqlClient.SqlException: 超时已过。超时时间 在完成之前经过 操作或服务器不 回应。

问题:为什么要对存储过程执行 ALTER,而不实际更改其中的任何内容,将完成时间恢复到不到一秒,正如预期的那样?

编辑:澄清一下,当应用程序运行缓慢时,它同时在具有相同参数的 SSMS 中运行良好。我能辨别的唯一区别是登录凭据(下次我注意到这种行为时,我将使用相同的凭据从 SSMS 进行检查)。最终目标是让 proc 以预期的速度持续运行,而无需偶尔干预。

解决方案:我想更新此问题,以防其他人遇到此问题。按照以下答案的线索,我能够始终如一地重现这种行为。为了测试,我使用sp_recompile 并将其传递给易受攻击的存储过程之一。然后我从浏览器发起一个网站请求,该请求将使用非典型参数调用存储过程。最后,我向一个使用典型参数调用 sproc 的页面发起网站请求,并观察到由于 sproc 调用的 SQL 超时,该请求没有完成。

为了在 SQL Server 2005 上解决此问题,我在我的 SELECT 中添加了 OPTIMIZE FOR 提示。易受攻击的存储过程都具有this article 中描述的“一体化”模式。这种模式当然不理想,但考虑到项目的时间框架,这是一个必要的权衡。

【问题讨论】:

    标签: .net sql-server performance stored-procedures


    【解决方案1】:

    参数嗅探和计划重用。时不时你会得到一个糟糕的计划。执行 ALTER 会影响过程中的元数据版本,因此计划必须在下次执行时重新编译。解决方案取决于多种因素,你可能有糟糕的 SQL,你可能会得到一个不幸的“优化”,我们不可能知道。识别过程中的语句是慢的,什么时候是慢的。 SQL Profiler 是您的朋友,例如跟踪 SP:StmtCompleted eevnt 的持续时间 > 5000。

    【讨论】:

    • 感谢您的帮助。我不是 SQL 专家;关于为什么它在 SSMS 中运行良好(使用相同的参数)的任何解释?
    • 不同的连接设置,不同的用户凭据,统计数据同时更新,幸运地在缓存中找到了一个好的计划。可能有很多原因。
    • 那么我是否正确理解使用同一个驱动程序与服务器通信,只是驱动程序和调用细节的配置如何?令我困惑的是,虽然该过程在站点上运行缓慢,但它同时在 SSMS 中运行良好(我能看到的唯一区别是 SQL 凭据)。这似乎排除了幸运计划或统计更新。
    • 驱动程序不是那么重要,但各种连接设置(ANSI、ANSY NULLS 等)和凭据很重要。计划不能在不同设置之间重复使用。 SQL 引擎通常会在内存中为相同的过程提供数十个计划。检查 sys.dm_exec_sessions 以获取 SSMS spid 和 App spid。 msdn.microsoft.com/en-us/library/ms176013.aspx
    • 技术上准确一点:驱动本身并不重要,但各种驱动有不同的默认值,SqlClient、ODBC、OleDB、JDBC、PHP、FreeTDS等驱动在默认值方面存在差异.
    【解决方案2】:

    执行计划可能已重新生成。

    有多种方法可以强制重新生成它,还有避免参数嗅探的方法,其中执行计划是根据参数确定的,但可能不适合所有输入。如果您在 2008 年,我建议您使用 OPTIMIZE FOR UNKNOWN 选项。

    或者,使用局部变量屏蔽所有输入变量以避免参数嗅探,并考虑调用 WITH RECOMPILE 或以这种方式声明 SP。

    另外,请确保您的统计信息是最新的。过时的统计数据可能意味着计划不再有效。

    Remus 的回答中的 cmets 还指出了一些可能影响服务器选择哪个计划的因素。

    【讨论】:

    • 感谢您的帮助...知道为什么它会在具有相同参数的 SSMS 中快速运行吗?
    • 我会尝试使用重新编译,正如 Remus 也提到的,输入屏蔽。谢谢。
    【解决方案3】:

    当您说查询在 SSMS 中运行良好时,请考虑以下几点:

    1. 查询计划是根据查询字符串的精确逐字节结构缓存的,包括空格
    2. 带有参数的查询的计划可能不同于带有固定值的查询(#1 的推论)

    您可以尝试使用 SQL Profiler,然后将整个慢查询从那里复制并粘贴到 SSMS 中,看看它是否仍然很慢。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-08-09
      • 2016-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多