web-dev-qa-db-ja.com

SQLデッドロック-同時に呼び出される同じストアドプロシージャ

私は比較的複雑なシステムを使用しています。静的テーブルは必要に応じて複数のデータソースから更新されます。データの動的な読み込みには4〜5秒かかり、結果をユーザーにすばやく表示するためです。

プロセス:

  1. ユーザーまたはアプリケーションが特定の注文を開く
  2. データを取得するためにストアドプロシージャが呼び出されます(dbo.Get_Dataと呼びます)。
  3. dbo.Get_Dataはイベントログをチェックして、前回データを検索してから変更があったかどうかを確認します
  4. 新しいイベントが見つかると、コストのかかるクエリを実行してデータを更新します
  5. データが返されます
IF (    SELECT [LastStaticUpdateEvent] < [LastSaveEvent] 
        FROM [dbo].[Events] 
        WHERE [OrderNumber] = @OrderNumber
    )
    BEGIN
       -- Update Static table
       UPDATE [Static]
       SET [Static].[A] = [App].[A]
          ,[Static].[B] = [App].[B]
       FROM [dbo].[AppData]            AS [App]   -- View with many joins (4-5 secs)
       INNER JOIN [dbo].[StaticResuts] AS [Static]
           ON [Static].[OrderNumber] = [App].[OrderNumber]
       WHERE [App].[OrderNumber] = @OrderNumber

       -- Update Event Log
       UPDATE [dbo].[Events]
       SET [LastStaticUpdateVent] = SYSDATETIME()
       WHERE [OrderNumber] = @OrderNumber

    END

SELECT * FROM [dbo].[StaticResults]

問題は、このデータを同時に要求できることです。最初のUPDATEが完了する前に、ユーザーAとユーザーBの両方がdbo.Get_Dataを呼び出すと、デッドロックが発生します。

ルックアップを続行する前に、最初の呼び出しが完了するまで2番目の呼び出しを待機させる適切なメソッドまたはパターンはありますか?

3
Kevin

ルックアップを続行する前に、最初の呼び出しが終了するまで2番目の呼び出しを待機させる適切なメソッドまたはパターンはありますか?

一度に1つのセッションでのみ実行できるコードブロックを作成する最も簡単な方法は、 アプリケーションロック を使用することです。 SQL Serverのロックエンジンを使用できますが、特定の行、ページ、またはテーブルをロックする代わりに、カスタム名でロックを作成します。例えば

begin transaction;

--begin exclusive section
exec sp_getapplock @Resource = 'Get_Data Exclusive Lock', @LockMode = 'Exclusive';  

--do stuff in only one session

--end exclusive section
exec sp_releaseapplock @Resource = 'Get_Data Exclusive Lock';  


commit transaction;