2009-08-12 38 views
13

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

+1

您的SP是否有参数? – RBarryYoung 2009-08-12 13:28:33

回答

31

这是参数嗅探的足迹。在这里看到另一个关于它的讨论; SQL poor stored procedure execution plan performance - parameter sniffing

有几种可能的解决方法,包括增加WITH RECOMPILE到工作半个月左右的时间你的存储过程。

大多数情况下建议的修复(尽管它取决于你的查询和存储过程的结构)是直接在查询中使用的参数,而是将它们存储到本地变量,然后使用这些变量在查询。

+1

哇!感谢RBarry年轻! ..我只是修改我的proc使用本地变量,而不是参数和proc从10秒到0秒! – 2013-04-10 13:38:28

+1

这种情况发生在存储过程依赖于任何参数传递或运行时间而不同的情况下。一些先前计算出的查询计划最终在下次执行时完全错误。最好的解决方案是从存储过程中删除这些变体。如果'WITH RECOMPILE'有帮助,那么使用存储过程没有意义。它们存在于性能上,而不是结构化编程。如果你想做两件不同的事情,则创建两个存储过程。 – Jodrell 2014-03-06 11:31:04

+1

@Jodrell虽然你的评论的第一部分是正确的,但最后一部分是不正确的。存储过程在SQL Server中有多种用途,性能甚至不是最重要的。 – RBarryYoung 2014-03-06 13:53:42

0

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

+0

downvote的任何原因? – Russell 2010-04-16 04:06:01

0

我想这可能是下降到缓存。如果你运行存储过程两次是第二次更快?

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

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

1

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

exec sp_recompile 'YourSproc' 

然后运行存储过程并注意使用合理的paramters。

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

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

0

首先,它听起来不像SQL基于使用大量临时表(可以在内存中保存或持久化到tempdb - 无论SQL Server决定哪个是最好的)和游标的使用。

我的建议是看看您是否可以将sproc重写为基于集合的查询,而不是光标方法,这样可以提供更好的性能,并且更容易调整和优化。很明显,我不知道你的sproc是干什么的,只是告诉你这是多么的简单/可行。

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

此外,为了确保查询的真实性比SP快,您需要排除数据/执行计划缓存,从而使后续运行的查询速度更快。您可以清除缓存使用出来:

DBCC FREEPROCCACHE 
DBCC DROPCLEANBUFFERS 

但仅仅做到这一点的一个开发/测试数据库服务器上,而不是生产。 然后运行查询,记录统计信息(例如,来自分析器)。再次清除缓存。运行SP并比较统计数据。

+0

运行总计是使用游标时可能比基于集合的代码更快的几次之一。 – HLGEM 2009-08-12 13:23:40

0

1)当您运行首次查询可能需要更多的时间。还有一点是,如果您使用任何核心子查询,并且如果您对这些值进行硬编码,则它将只执行一次。当你没有对它进行硬编码并在程序中运行时,如果你试图从输入值中得出值,那么它可能需要更多时间。

2)在极少数情况下,它可以是由于对网络流量,也在这里我们将不具有在查询执行时间对于相同的输入数据的一致性。

2

我也看看参数嗅探。可能是proc需要以不同方式处理参数slighlty。

0

我通常开始使用 “打印GETDATE()+‘ - 步’”疑难解答这样的问题。这可以帮助我缩小花费最多的时间。您可以从查询分析器运行它的位置进行比较,并缩小问题的位置。

0

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

0

其由于参数嗅探。首先声明临时变量,并将传入变量值设置为临时变量,并在整个应用程序中使用临时变量,这里是一个例子。

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

尝试这种方法