SP需要15分钟,但执行时查询相同的结果会在1-2分钟内返回结果

时间:2009-08-12 09:52:33

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

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

11 个答案:

答案 0 :(得分:48)

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

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

大多数情况下的推荐修复(虽然它取决于查询和sproc的结构)是 NOT 直接在查询中使用您的参数,而是将它们存储到局部变量然后使用查询中的那些变量。

答案 1 :(得分:4)

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

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

尝试这种方法

答案 2 :(得分:2)

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

答案 3 :(得分:1)

尝试重新编译sproc以丢弃任何存储的查询计划

exec sp_recompile 'YourSproc'

然后运行你的sproc注意使用明智的参数。

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

也许值得重新计算任何统计数据。

答案 4 :(得分:1)

我通常会通过使用来解决这类问题 “print getdate()+' - step'”。这有助于我缩小花费最多时间。您可以从查询分析器的位置进行比较,并缩小问题所在的范围。

答案 5 :(得分:0)

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

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

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

答案 6 :(得分:0)

首先,基于使用多个临时表(可以保存在内存中,或者持久保存到tempdb - 无论SQL Server决定哪种方式最好),它听起来都不会像SQL那样表现得太好,以及游标的使用。

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

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

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

DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS

但是只在dev / test数据库服务器上执行此操作,而不是在生产中执行此操作。 然后运行查询,记录统计数据(例如,从分析器)。再次清除缓存。运行SP并比较统计数据。

答案 7 :(得分:0)

1)第一次运行查询时可能需要更多时间。还有一点是,如果您正在使用任何相关的子查询,并且如果您对这些值进行硬编码,则它将仅执行一次。如果您没有硬编码并通过该过程运行它,并且如果您尝试从输入值派生值,那么可能需要更多时间。

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

答案 8 :(得分:0)

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

答案 9 :(得分:0)

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

每当我们要优化SP时,我们都会寻找执行计划。但是对于您而言,您将看到SSMS的优化计划,因为只有通过Code调用时,它才会花费更多时间。

由于ARITHABORT选项,对于每个SP和Function,SQL Server都会生成两个估计的计划。一种用于SSMS,另一种用于外部实体(ADO Net)。

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

只需在SSMS中启用该选项并执行SP,您将看到SP也将需要12-13分钟才能到达SSMS。 开启ARITHABORT 执行YourSpName 设置ARITHABORT OFF

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

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

答案 10 :(得分:-1)

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

相关问题