2016-11-14 26 views
2

複数の行を1つにまとめたSQL Server 2014データベースにアプリケーションを接続しました。アプリケーションの実行中は、このデータベースへの他の接続はありません。SQL Serverのデッドロックの防止

まず、特定の期間内の行のチャンクを選択します。このクエリは、クラスタ化されたルックアップとマージされた非クラスタ化シーク(TIME列)を使用します。

select ... 
from FOO 
where TIME >= @from and TIME < @to and ... 

次に、これらの行をC#で処理し、変更を1回の更新と複数回の削除として書き込みます。これはチャンクごとに何度も発生します。これらは、クラスタ化されていないインデックスシークも使用します。

begin tran 

update FOO set ... 
where NON_CLUSTERED_ID = @id 

delete FOO where NON_CLUSTERED_ID in (@id1, @id2, @id3, ...) 

commit 

これを複数の並列チャンクで実行すると、デッドロックが発生します。 updatedeleteにはROWLOCKを使用しようとしましたが、チャンク間に重複がなくても何らかの理由でこれまで以上にデッドロックが発生しました。

updateTABLOCKX, HOLDLOCKを試しましたが、それは私が並列性の利点を失うように私はselectを並列に実行できないことを意味します。

どのように私はデッドロックを回避できますが、まだ複数の並列チャンクを処理することができますか?

この場合、selectNOLOCKを使用することは安全でしょうか。チャンク間に行が重複していないとします。その後、TABLOCKX, HOLDLOCKupdatedeleteをブロックするだけですか?

デッドロックが発生し、アプリケーションでクエリを再試行することを受け入れるだけでよいですか?

UPDATE(追加情報):すべてのデッドロックは、これまでupdatedelete相、selectでなしに起きています。私は今日解決されない場合、いくつかのデッドロックログを取得しようとします(正しいトレースフラグは以前は有効になっていませんでした)。

UPDATE:これらはROWLOCKで発生したデッドロックの2つの構成されているが、彼らは両方だけdelete文と、それが使用する非クラスタ化インデックスを参照してください。私は、これらのものを再現できないため、これらがテーブルのヒントなしで発生するデッドロックと同じかどうかはわかりません。

Deadlock 1 Deadlock 2

.XDLから必要な何かがあるのか​​どうかを尋ね、私は全部を取り付ける少し疲れましたよ。

+0

あなたの選択中に 'UPDLOCK'を主張しようとしましたか?そうすれば、デッドロックからあなたを守るはずです。可能であれば、デッドロックログの詳細を私たちと共有してください。 – Jens

+1

すべての処理をストアドプロシージャに移動できますか?スナップショットの隔離を有効にするだけで解決することもできますが、実際は自分が行っていることに依存します。 –

+0

@Jens残念ながら、今はデッドロックログを取得できません。デッドロックのために失敗したスレッドはすべて 'update'と' delete'フェーズにあったようですので、 'select'ロックを変更することはこのケースに影響することはまずありません。私は残念ながらデッドロックログを持っていないので、次回の試みでデッドロックトレースフラグを有効にできるかどうかを確認します。 @ Nick.McDermaid残念なことに、スナップショットの分離を使用できません。 –

答えて

0

デッドロックに関する一般的なアドバイス:異なる順序ですべてを同じ順序で実行すること、つまり、同じ順序でロックを取得することを確認してください。

Minimizing Deadlocksに関するmicrosoft.comのこの技術記事でも同じアドバイスを見つけることができます。最初にリストされている理由があります。同じ順序で

  • Accessオブジェクト。
  • トランザクションでのユーザーのやりとりを避けてください。
  • トランザクションを短く、1つのバッチにまとめます。
  • 低い分離レベルを使用してください。
  • 行のバージョン管理ベースの分離レベルを使用します。
  • READ_COMMITTED_SNAPSHOTデータベース・オプションをONに設定すると、読込みコミット済トランザクションが行のバージョニングを使用できるようになります。
  • スナップショット分離を使用します。
  • バインドされた接続を使用します。

カトーからの質問の後に更新:

同じ順序でロックを取得する方法を、ここで適用されますか?あなたは彼がそれをするために彼のSQLを変更する方法についてのアドバイスを持っていますか?

デッドロックに関係なくどのような環境で、常に同じです:AYBを待っているように、2つのプロセス(例えばA & B)が異なるために、複数のロック(X & Y言う)を取得するのを待っていませんXであり、AXを保持し、BYを保持している。

DELETEおよびUPDATEステートメントは、行またはインデックス範囲またはテーブルのロックを暗黙的に取得するため(エンジンが適切と考えるものに応じて)、ここで適用されます。

プロセスを分析して、ロックを別の順序で取得できるシナリオがあるかどうかを確認する必要があります。それでも何も表示されない場合は、analyze deadlocks using the SQL Server Profiler

デッドロックイベントをトレースするには、デッドロックグラフイベントクラスをトレースに追加します。このイベントクラスは、デッドロックに関連するプロセスおよびオブジェクトに関するXMLデータをトレース内のTextDataデータ列に設定します。 SQL Server Profilerは、後でSQL Server Management Studioで表示できるデッドロックXML(.xdl)ファイルにXMLドキュメントを抽出できます。すべてのデッドロックグラフイベントを含む単一のファイルにデッドロックグラフイベントを抽出するようにSQL Server Profilerを構成するか、ファイルを分割することができます。

+0

ここで同じ順序でロックを取得する方法は?あなたは彼がそれをするために彼のSQLを変更する方法についてのアドバイスを持っていますか? – Cato

+0

@Cato更新された答えで与えられた余分な文脈。 –

+0

デッドロックグラフを追加しました。両方とも 'delete'ステートメントを参照しているようです。 –

0

このコードの複数のインスタンスが並行して実行されないようにするには、更新トランザクションでsp_getapplockを使用します。これは、テーブルロックのヒントのように選択文をブロックしません。

ロックを取得するのに時間がかかる可能性がありますが、タイムアウトパラメータよりも長いため、依然として再試行ロジックをプログラムする必要があります。

更新トランザクションをsp_getapplockにラップする方法です。

BEGIN TRANSACTION; 
BEGIN TRY 

    DECLARE @VarLockResult int; 
    EXEC @VarLockResult = sp_getapplock 
     @Resource = 'some_unique_name_app_lock', 
     @LockMode = 'Exclusive', 
     @LockOwner = 'Transaction', 
     @LockTimeout = 60000, 
     @DbPrincipal = 'public'; 

    IF @VarLockResult >= 0 
    BEGIN 
     -- Acquired the lock 
     update FOO set ... 
     where NON_CLUSTERED_ID = @id 

     delete FOO where NON_CLUSTERED_ID in (@id1, @id2, @id3, ...) 

    END ELSE BEGIN 
     -- return some error code, so that the caller could retry 
    END; 

    COMMIT TRANSACTION; 
END TRY 
BEGIN CATCH 
    ROLLBACK TRANSACTION; 
    -- handle the error 
END CATCH; 

選択文は変更する必要はありません。

チャンク内のIDが重複していないと言っても、NOLOCKに対してはお勧めします。このヒントを使用すると、SELECTクエリは変更されているページをスキップして、いくつかのページを2回読み取ることができます。このような行動が許容される可能性は低いです。

+0

' sp_getapplock'のように見えますが、私の現在の実装よりも遅く、すべてのデッドロックをやり直す方が良いでしょう。 'NOLOCK'に関する情報をありがとう。 –

関連する問題