【问题标题】:SP taking 15 minutes, but the same query when executed returns results in 1-2 minutesSP 需要 15 分钟,但执行相同的查询时会在 1-2 分钟内返回结果
【发布时间】:2010-11-18 21:53:49
【问题描述】:

所以基本上我有这个相对较长的存储过程。基本的执行流程是将SELECTS INTO 一些数据放入用# 符号声明的临时表中,然后在这些表中运行游标,在使用CREATE 创建的第三个临时表中生成“运行总计”。然后这个生成的临时表与数据库中的其他表连接起来,在一些分组等之后生成结果。问题是这个 SP 一直运行良好,直到现在在 1-2 分钟内返回结果。现在突然需要 12-15 分钟。如果我从 SP 中提取查询并通过手动设置相同的参数在管理工作室中执行它,它会在 1-2 分钟内返回结果,但 SP 需要很长时间。知道会发生什么。我尝试生成查询和 SP 的实际执行计划,但由于游标无法生成。知道为什么 SP 需要这么长时间,而查询却不需要吗?

【问题讨论】:

  • 你的SP有参数吗?

标签: sql sql-server stored-procedures sql-server-2005 parameter-sniffing


【解决方案1】:

我建议这个问题与临时表的类型(# 前缀)有关。此临时表保存该数据库会话的数据。当您通过应用程序运行它时,临时表将被删除并重新创建。
您可能会发现在 SSMS 中运行时,它会保留会话数据并更新表而不是创建表。 希望有帮助:)

【讨论】:

    【解决方案2】:

    我猜这可能归结为缓存。如果你运行存储过程两次,第二次会更快吗?

    要进一步调查,您可以从管理工作室运行它们,存储过程和查询版本,并在管理工作室中打开显示查询计划选项,然后比较存储过程中哪个区域比作为查询运行时花费的时间更长.

    您也可以在此处发布存储过程,供人们提出优化建议。

    【讨论】:

      【解决方案3】:

      尝试重新编译存储过程以放弃任何存储的查询计划

      exec sp_recompile 'YourSproc'
      

      然后运行您的存储过程,注意使用合理的参数。

      还比较两种执行查询的方法之间的实际执行计划。

      可能还值得重新计算任何统计数据。

      【讨论】:

        【解决方案4】:

        首先,基于使用多个临时表(可以保存在内存中,或持久化到 tempdb - SQL Server 决定最好的任何内容),SQL 无论如何都不会表现得很好。 ,以及游标的使用。

        我的建议是看看您是否可以将存储过程重写为基于集合的查询而不是游标方法,这将提供更好的性能并且更容易调整和优化。显然,我不确切知道您的存储过程是做什么的,以表明这对您来说有多容易/可行。

        至于为什么 SP 比查询花费的时间更长 - 很难说。当您尝试每种方法时,系统上的负载是否相同?如果您在负载较轻时自行运行查询,则比在负载较重时运行 SP 时要好。

        此外,为了确保查询确实比 SP 更快,您需要排除数据/执行计划缓存,这会使后续运行的查询更快。您可以使用以下命令清除缓存:

        DBCC FREEPROCCACHE
        DBCC DROPCLEANBUFFERS
        

        但只能在开发/测试数据库服务器上执行此操作,而不是在生产环境中。 然后运行查询,记录统计信息(例如来自分析器)。再次清除缓存。运行 SP 并比较统计数据。

        【讨论】:

        • 运行总计是少数使用游标可能比基于集合的代码更快的情况之一。
        【解决方案5】:

        1) 首次运行查询时,可能需要更多时间。还有一点是,如果您正在使用任何相关子查询,并且如果您对值进行硬编码,它将只执行一次。如果您没有对其进行硬编码并通过该过程运行它,并且如果您尝试从输入值中获取值,则可能需要更多时间。

        2) 在极少数情况下,这可能是由于网络流量造成的,而且对于相同的输入数据,我们的查询执行时间也会不一致。

        【讨论】:

          【解决方案6】:

          我还会研究参数嗅探。可能是 proc 需要以不同的方式处理参数。

          【讨论】:

            【解决方案7】:

            这是参数嗅探的足迹。有关它的另一个讨论,请参见此处; SQL poor stored procedure execution plan performance - parameter sniffing

            有几种可能的修复方法,包括将 WITH RECOMPILE 添加到您的存储过程中,这大约可以工作一半。

            对于大多数情况(尽管它取决于查询和存储过程的结构)建议的解决方法是直接在查询中使用参数,而是将它们存储到局部变量中,然后使用查询中的这些变量。

            【讨论】:

            • 哇!谢谢巴里杨! .. 我刚刚修改了我的 proc 以使用局部变量而不是参数,并且 proc 从 10 秒变为 0 秒!
            • 当存储过程因传递的参数或运行时间而有很大差异时,就会发生这种情况。一些先前计算的查询计划最终在下一次执行时完全错误。最好的解决方案是从存储过程中删除这些变化。如果WITH RECOMPILE 有帮助,那么使用存储过程就没有意义了。它们的存在是为了性能,而不是结构化编程。如果你想做两件不同的事情,那就做两个存储过程。
            • @Jodrell 虽然您评论的第一部分是正确的,但最后一部分不是。存储过程在 SQL Server 中有多种用途,性能甚至不是最重要的。
            • 好的,它们对安全也很有用。我仍然断言,如果你想做两件不同的事情,那就做两个存储过程。
            • 这可行,但感觉很脏。在查询中使用参数似乎是合乎逻辑的,转移它们的值对我来说没有意义。我读了那篇文章,并没有把事情弄清楚。也许我应该坚持写代码,但没有人愿意再雇佣 DBA。
            【解决方案8】:

            我通常通过使用 “打印getdate()+'-步骤'”。这有助于我缩小花费最多时间的范围。您可以从查询分析器中运行它的位置进行比较,并缩小问题所在。

            【讨论】:

            • 我喜欢这种快速简便的跟踪方式
            【解决方案9】:

            我也遇到了一个问题,我们必须创建一些临时表,然后操作它们必须根据规则计算一些值,最后将计算值插入第三个表中。这一切如果放在单个 SP 中大约需要 20-25 分钟。因此,为了进一步优化它,我们将 sp 分解为 3 个不同的 sp,现在所花费的总时间约为 6-8 分钟。只需确定整个过程中涉及的步骤以及如何将它们分解为不同的 sp。通过使用这种方法,整个过程所花费的总时间肯定会减少。

            【讨论】:

              【解决方案10】:

              由于参数嗅探。首先声明临时变量并将传入的变量值设置为临时变量并在整个应用程序中使用临时变量下面是一个示例。

              ALTER PROCEDURE [dbo].[Sp_GetAllCustomerRecords]
              @customerId INT 
              AS
              declare @customerIdTemp INT
              set @customerIdTemp = @customerId
              BEGIN
              SELECT * 
              FROM   Customers e Where
              CustomerId = @customerIdTemp 
              End
              

              试试这个方法

              【讨论】:

              • +1 因为这解决了我的问题。 sproc 有一个 int 输入参数。当我将它复制到一个局部变量并在以下查询中使用它时 - 瞧!
              • 这对我很有用 - 将存储过程从 12 分钟缩短到 5 秒。
              【解决方案11】:

              这是因为参数剪切。但是如何确认呢?

              每当我们要优化 SP 时,我们都会寻找执行计划。但是在您的情况下,您将看到 SSMS 的优化计划,因为它仅在通过代码调用时才需要更多时间。

              对于每个 SP 和 Function,由于 ARITHABORT 选项,SQL 服务器会生成两个估计计划。一个用于 SSMS,第二个用于外部实体(ADO Net)。

              ARITHABORT 在 SSMS 中默认为关闭。因此,如果您想检查您的 SP 在从 Code 调用时使用的确切查询计划。

              只需在 SSMS 中启用该选项并执行您的 SP,您将看到 SP 也需要 12-13 分钟从 SSMS。 设置阿里萨博特 执行 YourSpName 设置 ARITHABORT 关闭

              要解决这个问题,您只需要更新估计查询计划。

              有几种方法可以更新估计查询计划。 1.更新表统计。 2.重新编译SP 3. 在 SP 中设置 ARITHABORT OFF,以便它始终使用为 SSMS 创建的查询计划(不推荐使用此选项) 有关更多选项,请参阅这篇很棒的文章 - http://www.sommarskog.se/query-plan-mysteries.html

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2016-01-05
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-09-28
                • 1970-01-01
                • 2019-02-18
                • 2018-02-13
                相关资源
                最近更新 更多