2013-02-27 17 views
7

Mam procedurę składowaną, którą wywołuję przy użyciu LinqToSQL. Nie robię nic specjalnego, np.Czas oczekiwania na procedurę przechowywania Linq, ale SSMS Szybki

MyDataContext db = new MyDataContext() 

var results = db.storedProcedure(param1, param2, param3) 

// Do stuff 

Po uruchomieniu procedury przechowywanej przy użyciu dokładnie tych samych parametrów uzyskuję wyniki od 2 do 6 sekund. Baza danych to zdalna baza danych.

Jednak po uruchomieniu procedura przechowywana trwa (po debugowaniu ....) 275 sekund! W normalnych warunkach daje następujące wyjątki:

[Win32Exception (0x80004005) Operacja oczekiwania dokładnego Out]

[SQLException (0x80131904) upłynął limit czasu. Limit czasu, który upłynął przed zakończeniem operacji lub serwer nie odpowiada.] System.Data.SqlClient.SqlConnection.OnError (wyjątek SqlException, połączenie Boolean breakConnection, działanie 1 wrapCloseInAction) +1753346 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action 1 wrapCloseInAction) +5295154 System.Data.SqlClient.TdsParser .ThrowExceptionAndWarning (TdsParserStateObject stateObj, logiczna callerHasConnectionLock, logiczna asyncClose) +242 System.Data.SqlClient.TdsParser.TryRun (runBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader datastream BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, logiczna & 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, Boolean asynchroniczny, Timeout Int32, Zadanie & zadaniowe, Boolean asyncWrite) +1325 systemowe .Data.SqlClient.SqlCommand.RunExecuteReader (CommandBehavior cmdBehavior, RunBehavior runBehavior, logiczna returnStream metoda String realizacji TaskCompletionSource`1, przekroczenie czasu Int32, zadanie & zadanie logiczna asyncWrite) +175 System.Data.SqlClient.SqlCommand.RunExecuteReader (CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, metoda String) +53 System.Data.SqlClient.SqlCommand.ExecuteReader (zachowanie CommandBehavior, metoda String) +134 System.Data.SqlClie nt.SqlCommand.ExecuteDbDataReader (zachowanie CommandBehavior) +41 System.Data.Common.DbCommand.ExecuteReader() +12 System.Data.Linq.SqlClient.SqlProvider.Execute (zapytanie Express, QueryInfo queryInfo, fabryka IObjectReaderFactory, Object [] parentArgs, Object [] userArgs, ICompiledSubQuery [] subQueries, Object lastResult) +1306 System.Data.Linq.SqlClient.SqlProvider.ExecuteAll (zapytanie Express, QueryInfo [] queryInfos, fabryka IObjectReaderFactory, Object [] userArguments, ICompiledSubQuery [] subQueries) +118 System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute (zapytanie Expression) +342 System.Data.Linq.DataContext.ExecuteMethodCall (Obiekt instancji, MethodInfo methodInfo, Object [] parametry) +83

Wszystkie inne procedury przechowywane są wywoływane w ten sam sposób, ale żaden z nich nie ma tego problemu. Zdalny administrator DB twierdzi, że widzi rozpoczęcie i zakończenie połączenia przed upływem limitu czasu, więc wydaje się, że ma to coś wspólnego z krokami, w których Linq otrzymuje dane.

Czy ktoś już wcześniej tego doświadczył i pomysły na jego rozwiązanie?

Próbowałem usunąć SP z pliku dmbl i ponownie go dodać.Zauważyła zmianę jednej z wartości z dziesiętnej na podwójną, ale poza tym jest taka sama.

Jak zwykle wczoraj działało dobrze!

Z góry dziękuję.

Odpowiedz

3

OK, w końcu odkryłem PRAWDZIWĄ odpowiedź na ten problem. SSMS zazwyczaj korzysta z ARITHABORT ON, a kod zazwyczaj używa ARITHABORT OFF - jest to w zasadzie opcja radzenia sobie z tym, co się dzieje, gdy linia matematyczna w kodzie zawiera błąd - np. dzielony przez zero.

Najważniejsze jest jednak to, że obie metody mają inny plan wykonania - dlatego to samo (losowo) może trwać dłużej na stronie niż w SSMS.

Plany wykonania są kompilowane na podstawie szacunków za pierwszym razem, więc jest to, że plan wykonania jest buforowany w straszny sposób, który pasuje do pierwszego zapytania, ale jest straszny dla kolejnych zapytań. Tak właśnie się stało i właśnie dlatego nagle zaczęło działać ponownie - nowy plan kwerend został utworzony po zmianie procedury składowanej.

W końcu użyliśmy Z RECOMPILE w procedurze przechowywanej - więc nie ma efektywnego ponownego wykorzystania planu wykonania, ale i tak nie zauważyliśmy żadnej różnicy, a problem nie wystąpił od tego czasu.

0

Przyczyną tego problemu była dla mnie pętla, która polegała na Linq.Table < > .Count(). W środowisku programistycznym zapytanie podstawowe jest niemal natychmiastowe, ale w produkcji zajęło to kilka sekund. Po podłączeniu programu SQL Profiler okazało się, że kwerenda była wykonywana przy każdej iteracji pętli, więc te "kilka sekund" zaczęło się sumować, a ostatecznie przekroczyło limit czasu.

Rozwiązaniem dla mnie było przypisanie wyniku Count() do zmiennej lokalnej i użycie tego w pętli, aby Count() nie powtórzyło wykonania zapytania z każdą iteracją. Wyobrażam sobie, że inni ludzie mogą napotkać ten problem, jeśli polegają na wbudowanych funkcjach agregujących Linq, które ponownie uruchomią powolne zapytania.

Powiązane problemy