2013-02-27 16 views
7

Ho una procedura memorizzata che sto chiamando utilizzando LinqToSQL. Non sto facendo nulla di speciale, ad es.Timeout stored procedure Linq ma SSMS Quick

Quando eseguo la stored procedure utilizzando gli stessi identici parametri ottengo risultati tra 2 e 6 secondi. Il database è un database remoto.

Tuttavia, quando eseguo la stored procedure ci vuole (dopo il debugging ....) 275 secondi! In circostanze normali questo dà la seguente eccezione:

[Win32Exception (0x80004005): L'operazione di attesa scaduta]

[SqlException (0x80131904): Timeout scaduto. Il periodo di timeout trascorso prima del completamento dell'operazione o il server non risponde.] System.Data.SqlClient.SqlConnection.OnError (eccezione SqlException, breakConnection booleano, Azione 1 1 wrapCloseInAction) +1753346 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action wrapCloseInAction) 5.295.154 System.Data.SqlClient.TdsParser .ThrowExceptionAndWarning (stateObj TdsParserStateObject, booleano callerHasConnectionLock, booleano asyncClose) 242 System.Data.SqlClient.TdsParser.TryRun (runBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader datastream, bulkCopyHandler BulkCopySimpleResultSet, stateObj TdsParserStateObject, booleano & dataReady) 1682 System.Data .SqlClient.SqlDataReader.TryConsumeMetaData() +59 System.Data.SqlClient.SqlDataReader.get_MetaData() +90 System.Data.SqlClient.SqlCommand.Finish ExecuteReader (ds SqlDataReader runBehavior runBehavior, String) resetOptionsString +365 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds (cmdBehavior CommandBehavior, runBehavior runBehavior, returnStream booleano, async booleano, Int32 timeout, Task & compito, booleano asyncWrite) 1325 di sistema .Data.SqlClient.SqlCommand.RunExecuteReader (cmdBehavior CommandBehavior, runBehavior runBehavior, returnStream booleano, il metodo String, TaskCompletionSource`1 completamento, Int32 timeout, Task & compito, booleano asyncWrite) 175 System.Data.SqlClient.SqlCommand.RunExecuteReader (CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) +53 System.Data.SqlClient.SqlCommand.ExecuteReader (Comportamento Comportamento, metodo String) +134 System.Data.SqlClie nt.SqlCommand.ExecuteDbDataReader (Comportamento Comportamento) +41 System.Data.Common.DbCommand.ExecuteReader() +12 System.Data.Linq.SqlClient.SqlProvider.Execute (query di espressione, QueryInfo queryInfo, factory IObjectReaderFactory, Object [] parentArgs, Object [] userArgs, ICompiledSubQuery [] subQueries, Object lastResult) +1306 System.Data.Linq.SqlClient.SqlProvider.ExecuteAll (query di espressione, QueryInfo [] queryInfos, IObjectReaderFactory di fabbrica, Object [] userArguments, ICompiledSubQuery [] subQueries) +118 System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute (query Expression) +342 System.Data.Linq.DataContext.ExecuteMethodCall (istanza Object, MethodInfo methodInfo, Object [] parametri) +83

Tutte le altre stored procedure vengono chiamate allo stesso modo, ma nessuna presenta questo problema. Il DB Admin remoto dice che può vedere l'inizio e il termine della chiamata prima che si verifichi il timeout, quindi sembra che abbia a che fare con i passi DOPO che Linq riceve i dati.

Qualcuno ha già sperimentato questo e qualche idea su come risolverlo?

Ho provato a rimuovere SP dal file dmbl e ad aggiungerlo di nuovo.Notò un cambiamento in uno dei valori da decimale a doppio, ma a parte quello è lo stesso.

Come sempre, ieri ha funzionato bene!

Grazie in anticipo.

risposta

3

Ok, ho finalmente scoperto la REALE risposta a questo problema. In genere SSMS utilizza un ARITHABORT ON e il codice in genere utilizza ARITHABORT OFF - questa è fondamentalmente un'opzione per come gestire ciò che accade se una riga matematica nel codice ha un errore - ad es. dividere per zero.

La cosa principale qui, però, è che entrambi i metodi hanno un piano di esecuzione diverso - motivo per cui la stessa cosa può (a caso) richiedere molto più tempo sul sito web che in SSMS.

I piani di esecuzione vengono compilati in base a stime della prima volta in cui vengono utilizzati, quindi ciò che si trova casualmente è che il piano di esecuzione viene memorizzato in modo terribile per la prima query ma è orribile per le query successive. Questo è quello che è successo qui ed è anche il motivo per cui ha improvvisamente iniziato a funzionare di nuovo: un nuovo piano di query è stato creato dopo aver modificato la procedura memorizzata.

Alla fine abbiamo utilizzato WITH RECOMPILE nella stored procedure, quindi non esiste un riutilizzo efficiente del piano di esecuzione, ma non abbiamo notato alcuna differenza e il problema non si è verificato da allora.

0

Ciò che mi ha causato questo problema era un loop basato su Linq.Table < > .Count(). Nell'ambiente di sviluppo, la query sottostante è quasi istantanea, ma in produzione sono stati necessari alcuni secondi. Il collegamento di SQL Profiler ha rivelato che la query è stata eseguita a ogni iterazione del ciclo, quindi quei "pochi secondi" hanno iniziato a sommarsi e alla fine sono scaduti.

La soluzione per me era assegnare il risultato Count() a una variabile locale e utilizzarlo nel ciclo, in modo che Count() non eseguisse di nuovo la query con ogni iterazione. Immagino che altre persone sperimenteranno questo problema se si basano su funzioni di aggregazione Linq incorporate che rieseguiranno query lente.