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)
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.
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
Je suppose que cela est causé par paramètrereniflement.
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).
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
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.