简体   繁体   English

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

[英]SP taking 15 minutes, but the same query when executed returns results in 1-2 minutes

So basically I have this relatively long stored procedure.所以基本上我有这个相对较长的存储过程。 The basic execution flow is that it SELECTS INTO some data into temp tables declared with he # sign and then runs a cursor through these tables a generate a 'running total' into a third temp table which is created using CREATE .基本的执行流程是它将一些数据SELECTS INTO到用#符号声明的临时表中,然后在这些表中运行游标,生成一个“运行总计”到使用CREATE创建的第三个临时表中。 Then this resulting temp table is joined with other tables in the DB to generated the result after some grouping etc. The problem is that this SP had been running fine until now returning results in 1-2 minutes.然后这个生成的临时表与数据库中的其他表连接以在一些分组等之后生成结果。问题是这个 SP 一直运行良好,直到现在在 1-2 分钟内返回结果。 And now suddenly its taking 12-15 minutes.现在突然需要 12-15 分钟。 If I extract the query from the SP and executed it in the management studio by manually setting the same parameters it returns results in 1-2 minutes but the SP takes very long.如果我从 SP 中提取查询并通过手动设置相同的参数在管理工作室中执行它,它会在 1-2 分钟内返回结果,但 SP 需要很长时间。 Any idea what could be happening.知道会发生什么。 I tried to generate the Actual Execution plans of both the Query and the SP but it couldn't generate it because of the cursor.我试图生成查询和 SP 的实际执行计划,但由于游标而无法生成它。 Any idea why the SP takes so long while the query doesn't?知道为什么 SP 需要这么长时间而查询却没有吗?

This is the footprint of parameter-sniffing.这是参数嗅探的足迹。 See here for another discussion about it;有关它的另一个讨论,请参见此处; SQL poor stored procedure execution plan performance - parameter sniffing SQL糟糕的存储过程执行计划性能——参数嗅探

There are several possible fixes, including adding WITH RECOMPILE to your stored procedure which works about half the time.有几种可能的修复方法,包括将 WITH RECOMPILE 添加到您的存储过程中,这大约可以在一半的时间内工作。

The recommended fix for most situations (though it depends on the structure of your query and sproc) is to NOT use your parameters directly in your queries, but rather store them into local variables and then use those variables in your queries.对于大多数情况(尽管这取决于查询和 sproc 的结构),建议的修复方法是不要直接在查询中使用参数,而是将它们存储到局部变量中,然后在查询中使用这些变量。

its due to parameter sniffing.这是由于参数嗅探。 first of all declare temporary variable and set the incoming variable value to temp variable and use temp variable in whole application here is an example below.首先声明临时变量并将传入的变量值设置为临时变量,并在整个应用程序中使用临时变量,下面是一个示例。

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

try this approach试试这个方法

Try recompiling the sproc to ditch any stored query plan尝试重新编译 sproc 以丢弃任何存储的查询计划

exec sp_recompile 'YourSproc'

Then run your sproc taking care to use sensible paramters.然后运行您的 sproc,注意使用合理的参数。

Also compare the actual execution plans between the two methods of executing the query.还要比较执行查询的两种方法之间的实际执行计划。

It might also be worth recomputing any statistics.重新计算任何统计数据也可能是值得的。

I'd also look into parameter sniffing.我也会研究参数嗅探。 Could be the proc needs to handle the parameters slighlty differently.可能是 proc 需要以不同的方式处理参数。

I usually start troubleshooting issues like that by using "print getdate() + ' - step '".我通常通过使用“print getdate() + ' - step '”来解决此类问题。 This helps me narrow down what's taking the most time.这有助于我缩小花费最多时间的范围。 You can compare from where you run it from query analyzer and narrow down where the problem is at.您可以从查询分析器中运行它的位置进行比较,并缩小问题所在的范围。

I would guess it could possible be down to caching.我猜这可能归结为缓存。 If you run the stored procedure twice is it faster the second time?如果您运行存储过程两次,第二次会更快吗?

To investigate further you could run them both from management studio the stored procedure and the query version with the show query plan option turned on in management studio, then compare what area is taking longer in the stored procedure then when run as a query.要进一步调查,您可以从管理工作室的存储过程和查询版本中运行它们,并在管理工作室中打开显示查询计划选项,然后比较存储过程中哪个区域比作为查询运行时花费的时间更长。

Alternativly you could post the stored procedure here for people to suggest optimizations.或者,您可以在此处发布存储过程,供人们提出优化建议。

For a start it doesn't sound like the SQL is going to perform too well anyway based on the use of a number of temp tables (could be held in memory, or persisted to tempdb - whatever SQL Server decides is best), and the use of cursors.首先,基于使用多个临时表(可以保存在内存中,或持久化到 tempdb - 无论 SQL Server 决定什么是最好的),SQL 听起来都不会表现得很好,并且游标的使用。

My suggestion would be to see if you can rewrite the sproc as a set-based query instead of a cursor-approach which will give better performance and be a lot easier to tune and optimise.我的建议是看看您是否可以将 sproc 重写为基于集合的查询而不是游标方法,这将提供更好的性能并且更容易调整和优化。 Obviously I don't know exactly what your sproc does, to give an indication as to how easy/viable this is for you.显然,我并不确切知道您的 sproc 是做什么的,以表明这对您来说有多容易/可行。

As to why the SP is taking longer than the query - difficult to say.至于为什么 SP 需要比查询更长的时间 - 很难说。 Is there the same load on the system when you try each approach?当您尝试每种方法时,系统上的负载是否相同? If you run the query itself when there's a light load, it will be better than when you run the SP during a heavy load.如果您在负载较轻时运行查询本身,这会比在负载较重时运行 SP 时更好。

Also, to ensure the query truly is quicker than the SP, you need to rule out data/execution plan caching which makes a query faster for subsequent runs.此外,为了确保查询确实比 SP 更快,您需要排除数据/执行计划缓存,这使得后续运行的查询更快。 You can clear the cache out using:您可以使用以下方法清除缓存:

DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS

But only do this on a dev/test db server, not on production.但只能在开发/测试数据库服务器上执行此操作,而不是在生产上执行此操作。 Then run the query, record the stats (eg from profiler).然后运行查询,记录统计信息(例如来自分析器)。 Clear the cache again.再次清除缓存。 Run the SP and compare stats.运行 SP 并比较统计数据。

1) When you run the query for the first time it may take more time. 1) 当您第一次运行查询时,可能需要更多时间。 One more point is if you are using any corellated sub query and if you are hardcoding the values it will be executed for only one time.还有一点是,如果您正在使用任何相关的子查询,并且如果您对值进行硬编码,它将只执行一次。 When you are not hardcoding it and run it through the procedure and if you are trying to derive the value from the input value then it might take more time.当您不对其进行硬编码并通过该过程运行它时,如果您尝试从输入值中导出值,则可能需要更多时间。

2) In rare cases it can be due to network traffic, also where we will not have consistency in the query execution time for the same input data. 2) 在极少数情况下,这可能是由于网络流量造成的,对于相同的输入数据,我们在查询执行时间上也不会具有一致性。

I too faced a problem where we had to create some temp tables and then manipulating them had to calculate some values based on rules and finally insert the calculated values in a third table.我也遇到了一个问题,我们必须创建一些临时表,然后操作它们必须根据规则计算一些值,最后将计算出的值插入第三个表中。 This all if put in single SP was taking around 20-25 min.这一切如果放入单个 SP 大约需要 20-25 分钟。 So to optimize it further we broke the sp into 3 different sp's and the total time now taken was around 6-8 mins.因此,为了进一步优化它,我们将 sp 分成 3 个不同的 sp,现在花费的总时间约为 6-8 分钟。 Just identify the steps that are involved in the whole process and how to break them up in different sp's.只需确定整个过程中涉及的步骤以及如何将它们分解为不同的 sp。 Surely by using this approach the overall time taken by the entire process will reduce.当然,通过使用这种方法,整个过程所花费的总时间会减少。

This is because of parameter snipping.这是因为参数截断。 But how can you confirm it?但是你怎么能确认呢?

Whenever we supposed to optimize SP we look for execution plan.每当我们应该优化 SP 时,我们都会寻找执行计划。 But in your case, you will see an optimized plan from SSMS because it's taking more time only when it called through Code.但在您的情况下,您将看到来自 SSMS 的优化计划,因为只有在通过代码调用时才会花费更多时间。

For every SP and Function, the SQL server generates two estimated plans because of ARITHABORT option.对于每个 SP 和函数,由于 ARITHABORT 选项,SQL 服务器生成两个估计计划。 One for SSMS and second is for the external entities(ADO Net).一个用于 SSMS,第二个用于外部实体 (ADO Net)。

ARITHABORT is by default OFF in SSMS. ARITHABORT 在 SSMS 中默认关闭。 So if you want to check what exact query plan your SP is using when it calls from Code.因此,如果您想检查您的 SP 在从 Code 调用时使用的确切查询计划。

Just enable the option in SSMS and execute your SP you will see that SP will also take 12-13 minutes from SSMS.只需启用 SSMS 中的选项并执行您的 SP,您将看到 SP 也将从 SSMS 中花费 12-13 分钟。 SET ARITHABORT ON EXEC YourSpName SET ARITHABORT OFF SET ARITHABORT ON EXEC YourSpName SET ARITHABORT OFF

To solve this problem you just need to update the estimate query plan.要解决这个问题,您只需要更新估计查询计划。

There are a couple of ways to update the estimate query plan.有几种方法可以更新估计查询计划。 1. Update table statistics. 1. 更新表统计信息。 2. recompile SP 3. SET ARITHABORT OFF in SP so it will always use query plan created for SSMS (this option is not recommended) For more options please refer to this awesome article - http://www.sommarskog.se/query-plan-mysteries.html 2. 重新编译 SP 3. 在 SP 中设置 ARITHABORT OFF,因此它将始终使用为 SSMS 创建的查询计划(不推荐此选项)有关更多选项,请参阅这篇很棒的文章 - http://www.sommarskog.se/query-计划-mysteries.html

I would suggest the issue is related to the type of temp table (the # prefix).我建议该问题与临时表的类型(# 前缀)有关。 This temp table holds the data for that database session.此临时表保存该数据库会话的数据。 When you run it through your app the temp table is deleted and recreated.当您通过应用程序运行它时,临时表将被删除并重新创建。
You might find when running in SSMS it keeps the session data and updates the table instead of creating it.您可能会发现在 SSMS 中运行时,它会保留会话数据并更新表而不是创建它。 Hope that helps :)希望有帮助:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM