简体   繁体   English

查询运行速度很快,但在存储过程中运行缓慢

[英]Query runs fast, but runs slow in stored procedure

I am doing some tests using the SQL 2005 profiler. 我正在使用SQL 2005探查器进行一些测试。

I have a stored procedure which simply runs one SQL query. 我有一个存储过程,它只运行一个SQL查询。

When I run the stored procedure, it takes a long time and performs 800,000 disk reads. 当我运行存储过程时,它需要很长时间并执行800,000次磁盘读取。

When I run the same query separate to the stored procedure, it does 14,000 disk reads. 当我对存储过程分开运行相同的查询时,它会执行14,000次磁盘读取。

I found that if I run the same query with OPTION(recompile), it takes 800,000 disk reads. 我发现如果我使用OPTION(重新编译)运行相同的查询,则需要800,000次磁盘读取。

From this, I make the (possibly erroneous) assumption that the stored procedure is recompiling each time, and that's causing the problem. 由此,我做出(可能是错误的)假设,即存储过程每次都重新编译,这就是导致问题的原因。

Can anyone shed some light onto this? 任何人都可以对此有所了解吗?

I have set ARITHABORT ON. 我已经设置了ARITHABORT。 (This solved a similar problem on stackoverflow, but didn't solve mine) (这解决了stackoverflow上的类似问题,但没有解决我的问题)

Here is the entire stored procedure: 这是整个存储过程:

CREATE PROCEDURE [dbo].[GET_IF_SETTLEMENT_ADJUSTMENT_REQUIRED]
 @Contract_ID int,
 @dt_From smalldatetime,
 @dt_To smalldatetime,
 @Last_Run_Date datetime
AS
BEGIN
 DECLARE @rv int


 SELECT @rv = (CASE WHEN EXISTS
 (
  select * from 
  view_contract_version_last_volume_update
  inner join contract_version
  on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id
  where contract_version.contract_id=@Contract_ID
  and volume_date >= @dt_From
  and volume_date < @dt_To
  and last_write_date > @Last_Run_Date
 )
 THEN 1 else 0 end)

 -- Note that we are RETURNING a value rather than SELECTING it.
 -- This means we can invoke this function from other stored procedures
 return @rv
END

Here's a script I run that demonstrates the problem: 这是我运行的脚本,它演示了这个问题:

DECLARE 
 @Contract_ID INT,
 @dt_From smalldatetime,
 @dt_To smalldatetime,
 @Last_Run_Date datetime,
    @rv int


SET @Contract_ID=38
SET @dt_From='2010-09-01'
SET @dt_To='2010-10-01'
SET @Last_Run_Date='2010-10-08 10:59:59:070'


-- This takes over fifteen seconds
exec GET_IF_SETTLEMENT_ADJUSTMENT_REQUIRED @Contract_ID=@Contract_ID,@dt_From=@dt_From,@dt_To=@dt_To,@Last_Run_Date=@Last_Run_Date

-- This takes less than one second!
SELECT @rv = (CASE WHEN EXISTS
(
 select * from 
 view_contract_version_last_volume_update
 inner join contract_version
 on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id
 where contract_version.contract_id=@Contract_ID
 and volume_date >= @dt_From
 and volume_date < @dt_To
 and last_write_date > @Last_Run_Date
)
THEN 1 else 0 end)


-- With recompile option. Takes 15 seconds again!
SELECT @rv = (CASE WHEN EXISTS
(
 select * from 
 view_contract_version_last_volume_update
 inner join contract_version
 on contract_version.contract_version_id = view_contract_version_last_volume_update.contract_version_id
 where contract_version.contract_id=@Contract_ID
 and volume_date >= @dt_From
 and volume_date < @dt_To
 and last_write_date > @Last_Run_Date
)
THEN 1 else 0 end) OPTION(recompile)

OK, we have had similar issues like this before. 好的,我们之前遇到过类似的问题。

The way we fixed this, was by making local parameters inside the SP, such that 我们解决这个问题的方法是在SP内部创建局部参数

DECLARE @LOCAL_Contract_ID int, 
        @LOCAL_dt_From smalldatetime, 
        @LOCAL_dt_To smalldatetime, 
        @LOCAL_Last_Run_Date datetime

SELECT  @LOCAL_Contract_ID = @Contract_ID, 
        @LOCAL_dt_From = @dt_From, 
        @LOCAL_dt_To = @dt_To, 
        @LOCAL_Last_Run_Date = @Last_Run_Date

We then use the local parameters inside the SP rather than the parameters that was passed in. 然后我们使用SP内部的本地参数而不是传入的参数。

This typically fixed the issue for Us. 这通常解决了我们的问题。

We believe this to be due to parameter sniffing, but do not have any proof, sorry... X-) 我们认为这是由于参数嗅探,但没有任何证据,对不起...... X-)

EDIT: 编辑:

Have a look at Different Approaches to Correct SQL Server Parameter Sniffing for some insightful examples, explanations and fixes. 查看一些不同的方法来纠正SQL Server参数嗅探,以获得一些有见地的示例,解释和修复。

As others have mentioned, this could be a 'parameter sniffing' problem. 正如其他人所提到的,这可能是一个“参数嗅探”问题。 Try including the line: 尝试包括以下内容:

OPTION (RECOMPILE)

at the end of your SQL query. 在SQL查询结束时。

There is an article here explaining what parameter sniffing is: http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx 这里有一篇文章解释了什么参数嗅探: http//blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx

我想这是由参数 嗅探引起的

The issue of why a batch takes forever to run inside a SQL stored procedure yet runs instantaneously in SSMS has to do with SQL parameter sniffing, especially with datetime parameters. 为什么批处理永远在SQL存储过程中运行但在SSMS中即时运行的问题与SQL参数嗅探有关,尤其是对于datetime参数。

There are several excellent articles on parameter sniffing out there. 有几篇关于参数嗅探的优秀文章。

Here's one of them ( I didn't write it, just passing it on). 这是其中之一(我没有写它,只是传递它)。

http://www.sommarskog.se/query-plan-mysteries.html http://www.sommarskog.se/query-plan-mysteries.html

On my issue I've run: 在我的问题上,我跑了:

exec sp_updatestats 

and this speed up my sp from 120s to just 3s. 这使我的sp从120s加速到3s。 More info about Updating Statistics can be found here https://msdn.microsoft.com/en-us/library/ms173804.aspx 有关更新统计信息的更多信息,请访问https://msdn.microsoft.com/en-us/library/ms173804.aspx

I too got the same problem today. 我今天也遇到了同样的问题。 I have dropped and recreated the SP and it worked. 我已经删除并重新创建了SP并且它有效。 This is something with SP cache and when dropped the SP the cached plan has been removed. 这是SP缓存,当删除SP时,缓存的计划已被删除。 You can try the same or use 'DBCC FREEPROCCACHE' to delete cache. 您可以尝试相同或使用“DBCC FREEPROCCACHE”删除缓存。

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

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