web-dev-qa-db-fra.com

La requête s'exécute rapidement, mais s'exécute lentement dans la procédure stockée

Je fais des tests en utilisant le profileur SQL 2005.

J'ai une procédure stockée qui exécute simplement une requête SQL.

Lorsque j'exécute la procédure stockée, cela prend beaucoup de temps et effectue 800 000 lectures de disque.

Lorsque j'exécute la même requête séparément de la procédure stockée, il effectue 14 000 lectures de disque.

J'ai trouvé que si j'exécute la même requête avec OPTION (recompilation), cela prend 800 000 lectures de disque.

À partir de cela, je fais l'hypothèse (peut-être erronée) que la procédure stockée se recompile à chaque fois, ce qui cause le problème.

Quelqu'un peut-il éclairer cela?

J'ai activé ARITHABORT. (Cela a résolu un problème similaire sur stackoverflow, mais n'a pas résolu le mien)

Voici la procédure stockée entière:

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

Voici un script que j'exécute qui illustre le problème:

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)
39
Andrew Shepherd

OK, nous avons eu des problèmes similaires comme celui-ci auparavant.

La façon dont nous avons corrigé cela, était en faisant des paramètres locaux à l'intérieur du SP, de telle sorte que

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

Nous utilisons ensuite les paramètres locaux à l'intérieur du SP plutôt que les paramètres qui ont été passés.

Cela résout généralement le problème pour nous.

Nous pensons que cela est dû au reniflement des paramètres, mais nous n'avons aucune preuve, désolé ... X-)

MODIFIER:

Jetez un œil à Différentes approches pour corriger le reniflage des paramètres de SQL Server pour quelques exemples, explications et correctifs perspicaces.

79
Adriaan Stander

Comme d'autres l'ont mentionné, cela pourrait être un problème de "reniflage de paramètres". Essayez d'inclure la ligne:

OPTION (RECOMPILE)

à la fin de votre requête SQL.

Il y a un article ici expliquant ce qu'est le reniflage de paramètres: http://blogs.technet.com/b/mdegre/archive/2012/03/19/what-is-parameter-sniffing.aspx

7
ninjaPixel

Je suppose que cela est causé par paramètrereniflement.

5
Giorgi

La question de savoir pourquoi un lot prend une éternité à s'exécuter dans une procédure stockée SQL mais s'exécute instantanément dans SSMS a à voir avec le reniflage des paramètres SQL, en particulier avec les paramètres datetime.

Il existe plusieurs excellents articles sur le reniflage de paramètres.

En voici un (je ne l'ai pas écrit, je l'ai simplement transmis).

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

4
user1472721

Sur mon problème, j'ai couru:

exec sp_updatestats 

et cela accélère mon sp de 120s à seulement 3s. Plus d'informations sur la mise à jour des statistiques peuvent être trouvées ici https://msdn.Microsoft.com/en-us/library/ms173804.aspx

3
alaneo

Moi aussi, j'ai eu le même problème aujourd'hui. J'ai abandonné et recréé le SP et cela a fonctionné. C'est quelque chose avec SP cache et une fois le SP le le plan mis en cache a été supprimé. Vous pouvez essayer la même chose ou utiliser "DBCC FREEPROCCACHE" pour supprimer le cache.

2
SumanKumar