web-dev-qa-db-fra.com

La requête expire lorsqu'elle est exécutée à partir du Web, mais ultra-rapide lorsqu'elle est exécutée à partir de SSMS

J'essaie de déboguer la source d'un délai d'attente SQL dans une application Web que je gère. J'ai le code source du code C # derrière, donc je sais exactement quel code est en cours d'exécution. J'ai débogué l'application jusqu'à la ligne qui exécute le code SQL qui a expiré, et je regarde la requête s'exécuter dans le profileur SQL. 

Lorsque cette requête est exécutée à partir du Web, elle expire au bout de 30 secondes. Cependant, lorsque je coupe/colle la requête exactement telle que présentée dans Profiler, que je la mets dans SSMS et que je l'exécute, elle retourne presque instantanément. J'ai attribué le problème à ARITHABORT étant défini sur OFF dans la connexion utilisée par le Web (c'est-à-dire que, si j'active ARITHABORT dans la session SSMS, il fonctionne pendant une longue période et, si je le rallume, il s'exécute. très rapidement). Cependant, à la lecture de la description d’ARITHABORT, cela ne semble pas s’appliquer ... Je fais seulement un simple SELECT, et aucune arithmétique n’est exécutée du tout. Juste un simple INNER JOIN avec une condition WHERE:

Pourquoi ARITHABORT OFF serait-il à l’origine de ce comportement dans ce contexte ?? Est-il possible de modifier le paramètre ARITHABORT pour cette connexion à partir de SSMS? J'utilise SQL Server 2008.

39
Michael Bray

Votre code C # envoie donc une requête SQL ad hoc à SQL Server, avec quelle méthode? Avez-vous envisagé d'utiliser une procédure stockée? Cela assurerait probablement les mêmes performances (du moins dans le moteur), quel que soit le demandeur. 

Pourquoi? Le paramètre ARITHABORT est l’un des éléments examinés par l’optimiseur lorsqu’il détermine le mode d’exécution de votre requête (plus précisément, pour la correspondance de plan). Il est possible que le plan en cache ait le même paramètre que SSMS. Il utilise donc le plan mis en cache, mais avec le paramètre opposé, votre code C # impose une recompilation (ou vous atteignez peut-être un plan vraiment BAD dans la mémoire cache), ce qui peut certainement nuire aux performances dans de nombreux cas. 

Si vous appelez déjà une procédure stockée (vous n'avez pas envoyé votre requête, bien que je pense que vous vouliez le faire), vous pouvez essayer d'ajouter OPTION (RECOMPILE) à la requête (ou aux requêtes) incriminée (s) de la procédure stockée. Cela signifie que ces déclarations seront toujours recompilées, mais cela pourrait empêcher l'utilisation du mauvais plan que vous semblez frapper. Une autre option consiste à s'assurer que, lorsque la procédure stockée est compilée, le lot est exécuté avec SET ARITHABORT ON.

Enfin, vous semblez demander comment vous pouvez modifier le paramètre ARITHABORT dans SSMS. Je pense que ce que vous vouliez demander, c'est comment vous pouvez forcer le paramètre ARITHABORT dans votre code. Si vous décidez de continuer à envoyer du SQL ad hoc à partir de votre application C #, vous pouvez bien sûr envoyer une commande sous forme de texte comportant plusieurs instructions séparées par des points-virgules, par exemple:

SET ARITHABORT ON; SELECT ...

Pour plus d'informations sur les raisons de ce problème, consultez le superbe article de Erland Sommarskog:

38
Aaron Bertrand

Cette réponse inclut un moyen de résoudre ce problème:

En exécutant les commandes suivantes en tant qu'administrateur sur la base de données, toutes les requêtes s'exécutent comme prévu, quel que soit le paramètre ARITHABORT.

 DBCC DROPCLEANBUFFERS
 DBCC FREEPROCCACHE

Mettre à jour

Il semble que la plupart des gens finissent par avoir ce problème très rarement, et la technique ci-dessus est un correctif ponctuel décent. Mais si une requête spécifique présente ce problème plusieurs fois, une solution à plus long terme serait d'utiliser des indicateurs de requête tels que OPTIMIZE FOR et OPTION(Recompile), comme décrit dans cet article .

12
StriplingWarrior

J'ai eu ce problème plusieurs fois auparavant, mais si vous avez une procédure stockée avec le même problème, supprimer et recréer le proc stocké résoudront le problème.

Cela s'appelle le paramètre sniffing . Vous devez toujours localiser les paramètres dans le proc stocké pour éviter ce problème à l'avenir.

Je comprends que ce n’est peut-être pas ce que l’affiche originale veut, mais que cela puisse aider quelqu'un qui a le même problème.

3
Novice in.NET

Si vous utilisez Entity Framework, vous devez savoir que les paramètres de requête pour les valeurs de chaîne sont envoyés à la base de données en tant que nvarchar. Si la colonne de base de données à comparer est un varchar, elle PEUT, en fonction de votre classement, exiger une "CONVERSION IMPLICIT" évitant les index. 

Enfin découvert grâce à cet article: https://www.sqlskills.com/blogs/jonathan/implicit-conversions-that-cause-index-scans/

1
edumen

J'ai eu le même problème et il a été corrigé en exécutant la procédure "WITH RECOMPILE". Vous pouvez également essayer d’utiliser un paramètre de détection. Mon problème était lié au cache SQL. 

0
Manmeet

Si vous pouvez modifier votre code pour corriger le paramètre reniflement, optimisez pour un indice inconnu est votre meilleure option. Si vous ne pouvez pas modifier votre code, la meilleure option est exec sp_recompile 'nom du proc', ce qui obligera uniquement ce proc stocké à obtenir un nouveau plan d'exécution. Supprimer et recréer un proc aurait un effet similaire mais pourrait provoquer des erreurs si quelqu'un essayait de l'exécuter alors que vous l'aviez abandonné. DBCC FREEPROCCACHE supprime tous vos plans mis en cache, ce qui peut causer des dégâts considérables à votre système, y compris de nombreuses expirations de délais dans un environnement de production de transactions lourd. La définition de arithabort n’est pas une solution au problème, mais un outil utile pour déterminer si le sniffing des paramètres est en cause.

0
N. Rhoades

J'ai le même problème lorsque j'ai essayé d'appeler SP à partir de SMSS, cela a pris 2 secondes, alors que depuis l'application Web (ASP.NET), cela a pris environ 3 minutes.

J'ai essayé toutes les solutions suggérées sp_recompile, DBCC FREEPROCCACHE et DBCC DROPCLEANBUFFERS mais rien n'a résolu mon problème, mais lorsque vous avez essayé le paramètre renifler, tout a bien fonctionné. 

0
Karim Tawfik