2013-02-27 1 views
7

J'ai une procédure stockée que j'appelle en utilisant LinqToSQL. Je ne fais rien de spécial, par exemple. Lorsque j'exécute la procédure stockée en utilisant exactement les mêmes paramètres, j'obtiens des résultats entre 2 et 6 secondes. La base de données est une base de données distante. Cependant, lorsque j'exécute la procédure stockée, il faut (après le débogage ....) 275 secondes! Dans des circonstances normales, cela donne l'exception suivante:Délai de procédure stocké Linq mais SSMS rapide

[Win32Exception (0x80004005): L'opération d'attente a expiré]

[SqlException (0x80131904): Délai d'attente expiré. Le délai d'attente s'est écoulé avant la fin de l'opération ou le serveur ne répond pas.] System.Data.SqlClient.SqlConnection.OnError (Exception SqlException, Boolean breakConnection, Action 1 wrapCloseInAction) +1753346 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action 1 wrapCloseInAction) +5295154 System.Data.SqlClient.TdsParser .ThrowExceptionAndWarning (TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose) 242 System.Data.SqlClient.TdsParser.TryRun (runBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader DATASTREAM, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean & dataReady) 1682 System.Data .SqlClient.SqlDataReader.TryConsumeMetaData() +59 System.Data.SqlClient.SqlDataReader.get_MetaData() +90 System.Data.SqlClient.SqlCommand.Finish ExecuteReader (SqlDataReader ds, runBehavior runBehavior, String resetOptionsString) +365 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds (CommandBehavior cmdBehavior, runBehavior runBehavior, Boolean returnStream, async Boolean, Int32 délai d'attente, la tâche Task &, Boolean asyncWrite) 1325 système .Data.SqlClient.SqlCommand.RunExecuteReader (CommandBehavior cmdBehavior, runBehavior runBehavior, Boolean returnStream, la méthode de la chaîne, l'achèvement TaskCompletionSource`1, temporisation Int32, tâche Task &, Boolean asyncWrite) 175 System.Data.SqlClient.SqlCommand.RunExecuteReader (CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, méthode String) +53 System.Data.SqlClient.SqlCommand.ExecuteReader (Comportement CommandBehavior, méthode String) +134 System.Data.SqlClie nt.SqlCommand.ExecuteDbDataReader (comportement CommandBehavior) +41 System.Data.Common.DbCommand.ExecuteReader() +12 System.Data.Linq.SqlClient.SqlProvider.Execute (requête d'expression, QueryInfo queryInfo, fabrique IObjectReaderFactory, Object [] parentArgs, Object [] userArgs, sous-requêtes ICompiledSubQuery [], objet lastResult) +1306 System.Data.Linq.SqlClient.SqlProvider.ExecuteAll (requête d'expression, QueryInfo [] queryInfos, fabrique IObjectReaderFactory, Object [] userArguments, sous-requêtes ICompiledSubQuery []) +118 System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute (requête d'expression) +342 System.Data.Linq.DataContext.ExecuteMethodCall (instance d'objet, MethodInfo methodInfo, Object [] paramètres) +83

Toutes les autres procédures stockées sont appelées de la même manière, mais aucune n'a ce problème. L'administrateur de la base de données distante indique qu'il peut voir l'appel démarrer et se terminer avant que le délai d'attente ne se produise, il semble donc avoir quelque chose à voir avec les étapes APRÈS que Linq ait reçu les données.

Est-ce que quelqu'un a déjà eu cette expérience et des idées pour la résoudre?

J'ai essayé d'enlever le SP du fichier dmbl et de le rajouter.Il a remarqué un changement de l'une des valeurs de décimale à double, mais à part ça c'est tout de même.

Comme toujours, ça fonctionnait bien hier!

Merci d'avance.

Répondre

3

Ok, j'ai finalement découvert la vraie réponse à ce problème. SSMS utilise généralement ARITHABORT ON et le code utilise généralement ARITHABORT OFF - il s'agit essentiellement d'une option pour savoir comment gérer ce qui se passe si une ligne mathématique dans le code a une erreur - par ex. diviser par zéro. La principale chose ici, cependant, est que les deux méthodes ont un plan d'exécution différent - ce qui explique pourquoi la même chose peut (beaucoup trop) prendre beaucoup plus de temps sur le site Web que dans le SSMS. Les plans d'exécution sont compilés en fonction des estimations de la première utilisation, ce que vous trouvez au hasard est que le plan d'exécution est mis en cache d'une manière terrible qui convient à votre première requête mais est horrible pour les requêtes suivantes. C'est ce qui s'est passé ici et c'est aussi pourquoi il a soudainement recommencé à fonctionner - un nouveau plan de requête a été créé après la modification de la procédure stockée. En fin de compte, nous avons utilisé WITH RECOMPILE dans la procédure stockée - il n'y a donc pas de réutilisation efficace du plan d'exécution, mais nous n'avons remarqué aucune différence et le problème ne s'est pas produit depuis.

0

Ce qui a causé ce problème pour moi était une boucle qui comptait sur Linq.Tableau < > .Count(). Dans l'environnement de développement, la requête sous-jacente est presque instantanée, mais en production, elle a pris quelques secondes. L'association de SQL Profiler a révélé que la requête a été exécutée à chaque itération de la boucle, de sorte que ces "quelques secondes" ont commencé à s'accumuler et ont finalement expiré. La solution pour moi était d'affecter le résultat Count() à une variable locale, et l'utiliser dans la boucle, de sorte que Count() n'a pas réexécuté la requête à chaque itération. J'imagine que d'autres personnes rencontreront ce problème si elles s'appuient sur des fonctions agrégées Linq intégrées qui vont ré-exécuter des requêtes lentes.

Questions connexes