web-dev-qa-db-fra.com

SP prenant 15 minutes, mais la même requête lors de l'exécution renvoie des résultats en 1-2 minutes

Donc, fondamentalement, j'ai cette procédure stockée relativement longue. Le flux d'exécution de base est qu'il SELECTS INTO quelques données dans les tables temporaires déclarées avec he # signe puis exécute un curseur dans ces tables et génère un "total cumulé" dans une troisième table temporaire créée à l'aide de CREATE. Ensuite, cette table temporaire résultante est jointe à d'autres tables de la base de données pour générer le résultat après un certain regroupement, etc. Le problème est que cette SP fonctionnait bien jusqu'à présent, renvoyant des résultats en 1-2 minutes . Et maintenant, tout à coup, cela prend 12-15 minutes. Si j'extrait la requête du SP et l'exécute dans le studio de gestion en définissant manuellement les mêmes paramètres, elle renvoie des résultats en 1-2 minutes mais le SP prend très longtemps. Toute idée de ce qui pourrait se produire. J'ai essayé de générer les plans d'exécution réelle de la requête et du SP mais cela ne pouvait pas t le générer à cause du curseur. Une idée pourquoi le SP prend autant de temps alors que la requête ne fonctionne pas?

27

C'est l'empreinte du reniflage de paramètres. Voir ici pour une autre discussion à ce sujet; Performances du plan d'exécution des procédures stockées pauvres en SQL - reniflage des paramètres

Il existe plusieurs correctifs possibles, notamment l'ajout de WITH RECOMPILE à votre procédure stockée, qui fonctionne environ la moitié du temps.

Le correctif recommandé pour la plupart des situations (bien que cela dépende de la structure de votre requête et de votre sproc) est de [~ # ~] pas [~ # ~] utilisez vos paramètres directement dans vos requêtes, mais plutôt stockez-les dans des variables locales, puis utilisez ces variables dans vos requêtes.

51
RBarryYoung

son dû au reniflement de paramètre. Tout d'abord, déclarez une variable temporaire et définissez la valeur de la variable entrante sur variable temporaire et utilisez la variable temporaire dans toute l'application. Voici un exemple ci-dessous.

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

essayez cette approche

5
Ammar

J'examinerais également le reniflement des paramètres. Il se peut que le proc doive gérer les paramètres légèrement différemment.

2
HLGEM

Essayez de recompiler le sproc pour abandonner tout plan de requête stocké

exec sp_recompile 'YourSproc'

Exécutez ensuite votre sproc en prenant soin d'utiliser des paramètres raisonnables.

Comparez également les plans d'exécution réels entre les deux méthodes d'exécution de la requête.

Il pourrait également être utile de recalculer les statistiques.

1
pjp

Je commence généralement à résoudre des problèmes comme celui-ci en utilisant "print getdate () + '- step'". Cela m'aide à préciser ce qui prend le plus de temps. Vous pouvez comparer d'où vous l'exécutez à partir de l'analyseur de requêtes et affiner où se situe le problème.

1
Bill Martin

Moi aussi, j'ai été confronté à un problème où nous devions créer des tables temporaires, puis les manipuler pour calculer certaines valeurs en fonction de règles et enfin insérer les valeurs calculées dans une troisième table. Tout cela si mis en single SP prenait environ 20-25 min. Donc, pour l'optimiser davantage, nous avons divisé le sp en 3 sp différents et le temps total maintenant pris était d'environ 6-8 minutes. Identifiez simplement les étapes qui sont impliquées dans l'ensemble du processus et comment les décomposer en différents sp. Sûrement en utilisant cette approche, le temps global pris par l'ensemble du processus sera réduit.

0
HotTester

Je suppose que cela pourrait être dû à la mise en cache. Si vous exécutez la procédure stockée deux fois, est-ce plus rapide la deuxième fois?

Pour enquêter plus avant, vous pouvez les exécuter à la fois à partir de Management Studio, la procédure stockée et la version de la requête avec l'option Afficher le plan de requête activée dans Management Studio, puis comparer la zone qui prend plus de temps dans la procédure stockée, puis lorsqu'elle est exécutée en tant que requête.

Alternativement, vous pouvez publier la procédure stockée ici pour que les gens suggèrent des optimisations.

0
Gavin

Pour commencer, il ne semble pas que le SQL fonctionnera de toute façon trop bien basé sur l'utilisation d'un certain nombre de tables temporaires (pourrait être conservé en mémoire ou persisté sur tempdb - tout ce que SQL Server décidera le mieux), et le utilisation de curseurs.

Ma suggestion serait de voir si vous pouvez réécrire le sproc en tant que requête basée sur un ensemble au lieu d'une approche par curseur qui donnera de meilleures performances et sera beaucoup plus facile à régler et à optimiser. Évidemment, je ne sais pas exactement ce que fait votre sproc, pour vous indiquer à quel point cela est facile/viable pour vous.

Quant à savoir pourquoi le SP prend plus de temps que la requête - difficile à dire. Y a-t-il la même charge sur le système lorsque vous essayez chaque approche? Si vous exécutez la requête elle-même quand il y a une charge légère , ce sera mieux que lorsque vous exécutez le SP lors d'une lourde charge.

De plus, pour vous assurer que la requête est vraiment plus rapide que le SP, vous devez exclure la mise en cache du plan de données/d'exécution, ce qui accélère la requête pour les exécutions suivantes. Vous pouvez vider le cache en utilisant:

DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS

Mais ne le faites que sur un serveur db dev/test, pas sur la production. Exécutez ensuite la requête, enregistrez les statistiques (par exemple à partir du profileur). Videz à nouveau le cache. Exécutez le SP et comparez les statistiques.

0
AdaTheDev

1) Lorsque vous exécutez la requête pour la première fois, cela peut prendre plus de temps. Un autre point est que si vous utilisez une sous-requête corellée et si vous codez en dur les valeurs, elle ne sera exécutée qu'une seule fois. Lorsque vous ne le codez pas en dur et ne l'exécutez pas à travers la procédure et si vous essayez de dériver la valeur de la valeur d'entrée, cela peut prendre plus de temps.

2) Dans de rares cas, cela peut être dû au trafic réseau, également lorsque nous n'aurons pas de cohérence dans le temps d'exécution des requêtes pour les mêmes données d'entrée.

0
Jebli