web-dev-qa-db-ja.com

時々SqlExceptionを取得する:タイムアウトの期限切れ

サーバーでアプリケーションを実行しています。このアプリケーションの問題は、毎日10〜20を取得していることです。System.Data.SqlClient.SqlException Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding私のSPの1つだけ。これが私のSPです。

            ALTER PROCEDURE [dbo].[Insertorupdatedevicecatalog] 
                            (@OS                NVARCHAR(50) 
                            ,@UniqueID          VARCHAR(500)
                            ,@Longitude         FLOAT 
                            ,@Latitude          FLOAT
                            ,@Culture           VARCHAR(10)
                            ,@Other             NVARCHAR(200)
                            ,@IPAddress         VARCHAR(50)
                            ,@NativeDeviceID    VARCHAR(50))
            AS 
            BEGIN 

                DECLARE @OldUniqueID VARCHAR(500) = '-1';
                SELECT @OldUniqueID = [UniqueID] FROM DeviceCatalog WHERE (@NativeDeviceID != '' AND [NativeDeviceID] = @NativeDeviceID);

                BEGIN TRANSACTION [Tran1]
                    BEGIN TRY
                        IF EXISTS(SELECT 1 FROM DeviceCatalog WHERE [UniqueID] = @UniqueID) 
                        BEGIN 
                            UPDATE  DeviceCatalog 
                               SET  [OS] = @OS
                                   ,[Location] = geography::STGeomFromText('POINT(' + CONVERT(VARCHAR(100 ), @Longitude) + ' ' + CONVERT(VARCHAR(100), @Latitude) + ')', 4326)
                                   ,[Culture] = @Culture
                                   ,[Other] = @Other
                                   ,[Lastmodifieddate] = Getdate()
                                   ,[IPAddress] = @IPAddress
                            WHERE   [UniqueID] = @UniqueID;
                        END
                        ELSE 
                        BEGIN
                            INSERT INTO DeviceCatalog
                                        ([OS]
                                        ,[UniqueID]
                                        ,[Location] 
                                        ,[Culture] 
                                        ,[Other]
                                        ,[IPAddress]
                                        ,[NativeDeviceID])
                                VALUES  (@OS
                                        ,@UniqueID
                                        ,geography::STGeomFromText('POINT(' + CONVERT(VARCHAR(100) ,@Longitude) + ' ' + CONVERT(VARCHAR(100), @Latitude) + ')', 4326) 
                                        ,@Culture
                                        ,@Other
                                        ,@IPAddress
                                        ,@NativeDeviceID);
                                IF(@OldUniqueID != '-1' AND @OldUniqueID != @UniqueID)
                                BEGIN
                                    EXEC DeleteOldDevice @OldUniqueID, @UniqueID;
                                END
                        END
                        COMMIT TRANSACTION [Tran1];
                    END TRY
                    BEGIN CATCH
                        ROLLBACK TRANSACTION [Tran1];
                        DECLARE @ErrorNumber nchar(5), @ErrorMessage nvarchar(2048);
                        SELECT
                            @ErrorNumber = RIGHT('00000' + ERROR_NUMBER(), 5),
                            @ErrorMessage = @ErrorNumber + ' ' + ERROR_MESSAGE();
                        RAISERROR (@ErrorMessage, 16, 1);
                    END CATCH
            END

このSPに問題はありますか?このSPでのみタイムアウト例外が発生するのはなぜですか?スタックトレースは次のとおりです。

System.Data.SqlClient.SqlException (0x80131904): Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)
   at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning()
   at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj)
   at System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString)
   at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean async)
   at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result)
   at System.Data.SqlClient.SqlCommand.InternalExecuteNonQuery(DbAsyncResult result, String methodName, Boolean sendToPipe)
   at System.Data.SqlClient.SqlCommand.ExecuteNonQuery()
   at App.Classes.DBLayer.Execute(SqlCommand command, Boolean executeNonQuery)
   at App.Helpers.SQLHelper.GetResult(List`1 parameters, Boolean storedProcedure, String commandText, ResultType type)
   at App.Helpers.SQLHelper.ExecuteNonQuery(List`1 parameters, Boolean storedProcedure, String commandText)
   at App.Services.DeviceCatalogService.InsertOrUpdateDeviceCatalog(DeviceCatalog deviceCataLog)
   at WebApplication1.Handlers.RegisterDevice.ProcessRequest(HttpContext context)
   at System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
   at System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously)
19
user960567

サーバー側でこれを調査し、実行がタイムアウトする理由を理解する必要があります。サーバーにはタイムアウトがないことに注意してください。タイムアウトは、 _SqlCommand.CommandTimeout_ のデフォルトの30秒によって発生します。

適切なリソースは Waits and Queues です。これは、SQL Serverのパフォーマンスのボトルネックを診断する方法です。タイムアウトの実際の原因に基づいて、適切なアクションを実行できます。遅い実行(悪い計画)を処理しているかブロックしているかをまず確認する必要があります。

推測するなら、_IF EXISTS... UPDATE_の不健康なパターンが根本的な原因だと思います。このパターンは正しくないため、同時実行ではエラーが発生します。 _IF EXISTS_を同時に実行する2つの同時トランザクションは、両方とも同じ結論に達し、bothINSERTまたはUPDATEを試行します。データベースの既存の制約に応じて、デッドロック(ラッキーケース)または失われた書き込み(アンラッキーケース)になる可能性があります。ただし、適切な調査のみが実際の根本原因を明らかにします。 auto-growth events のように、まったく異なるものになる可能性があります。

また、プロシージャはCATCHブロックを誤って処理しています。 alwaysをチェックする必要があります XACT_STATE() をチェックするブロックが実行されます。また、トランザクションに名前を付けることから何を期待するかも明確ではありません。これは、名前付きトランザクションをセーブポイントと混同することに関連するよくある間違いです。正しいパターンについては、 例外処理とネストされたトランザクション を参照してください。

編集

これを調査する可能な方法は次のとおりです。

  1. 関連する CommandTimeout を0(無限)に変更します。
  2. _blocked process threshold_ を有効にし、30秒に設定します(以前のCommandTimeout)
  3. プロファイラーで ブロックされたプロセスレポートイベント を監視します
  4. ワークロードを開始する
  5. プロファイラーがレポートイベントを生成するかどうかを確認します。もしそうなら、彼らは原因を特定します。

これらのアクションにより、タイムアウトがブロックによるものである場合、タイムアウトが発生するたびに「ブロックされたプロセスレポート」イベントが発生します。アプリケーションは、ブロックが解除されるまで待機し続けます。ブロックの原因が live-lock である場合、アプリケーションは永久に待機します。

26
Remus Rusanu

接続文字列に次の行を追加します。

Connect Timeout=200; pooling='true'; Max Pool Size=200

myCom.CommandTimeout = 200も設定できます

大量のデータがある場合は、タイムアウト秒数を200秒から600秒に増やすこともできます。

これもweb.configで編集します。

[〜#〜] this [〜#〜] ドキュメントに従ってください。

8
Freelancer

これは、パラメータスニッフィングが原因で発生する可能性があります。したがって、ストアドプロシージャ内で宣言されたローカル変数を使用するだけです。それらを適切に使用します。

@ InVar1を宣言する...

.....

where condition = @ Invar1

1
Rahul Vadhan

たぶんOPTIMIZE FORまたはWITH RECOMPILEヒントがSQL例外タイムアウトの問題を解決する。

この記事では、その実装方法を説明し、「パラメータスニッフィング」の問題について説明します。

https://blogs.msdn.Microsoft.com/robinlester/2016/08/10/improving-query-performance-with-option-recompile-constant-folding-and-avoiding-parameter-sniffing-issues/

1
Edu Pelais