ASP.NET で重たいクエリをSQL Serverに投げたところ、タイムアウトしてしまいました。
その対処についての記録です。
ログには「Timeout に達しました。操作が完了する前にタイムアウト期間が過ぎたか、またはサーバーが応答していません。」のメッセージ。
スタックトレースはこんな感じ。
場所 System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
場所 System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
場所 System.Data.SqlClient.TdsParserStateObject.ReadSniError(TdsParserStateObject stateObj, UInt32 error)
場所 System.Data.SqlClient.TdsParserStateObject.ReadSniSyncOverAsync()
場所 System.Data.SqlClient.TdsParserStateObject.TryReadNetworkPacket()
場所 System.Data.SqlClient.TdsParserStateObject.TryPrepareBuffer()
場所 System.Data.SqlClient.TdsParserStateObject.TryReadByteArray(Byte[] buff, Int32 offset, Int32 len, Int32& totalRead)
場所 System.Data.SqlClient.TdsParserStateObject.TryReadByteArray(Byte[] buff, Int32 offset, Int32 len)
場所 System.Data.SqlClient.TdsParser.TrySkipValue(SqlMetaDataPriv md, Int32 columnOrdinal, TdsParserStateObject stateObj)
場所 System.Data.SqlClient.TdsParser.TrySkipRow(_SqlMetaDataSet columns, Int32 startCol, TdsParserStateObject stateObj)
場所 System.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
場所 System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
場所 System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async, Int32 timeout, Task& task, Boolean asyncWrite, SqlDataReader ds)
場所 System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean asyncWrite)
場所 System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(TaskCompletionSource`1 completion, String methodName, Boolean sendToPipe, Int32 timeout, Boolean asyncWrite)
場所 System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
時間に関する設定は3か所。
(1)web.configのconnectionString属性にConnection Timeout=180;を追記しました。
<connectionStrings>
<add name="DefaultConnection" connectionString="Data Source=XXXXX;Initial Catalog=XXXXX;Persist Security Info=False;Integrated Security=False;User Id=XXXXX;Password=XXXXX;Connection Timeout=180;" providerName="System.Data.SqlClient" />
</connectionStrings>
(2)web.configのhttpRuntimeにexecutionTimeout属性を追加し180秒に設定しました。
<system.web>
<httpRuntime executionTimeout="180" />
</system.web>
(3)ソースコードの中でコマンドのタイムアウト時間を180秒に設定
SqlCommand cmd = new SqlCommand("ExportCSV", cn);
・・・・中略
cmd.CommandTimeout = 180;
cmd.ExecuteNonQuery();
私は(3)のコマンドのタイムアウト時間について漏れていてハマりました。