6

データベースで複数の同時 CRUD 操作を実行している Java アプリケーションがあります。SQLServer のサポートを追加していますが、同時削除中のデッドロックに問題があります。調査の結果、問題は特定のテーブルでのロックのエスカレーションが原因である可能性があることがわかりました。

それを修正しようとして、デッドロックを回避できるように、UPDLOCK ヒントを使用して、問題のテーブルのすべての読み取りを「更新のために」行うことにしました。しかし、私はまだ問題を見ています。SQLServer でトレースを有効にしましたが、SQLServer ログに次のデッドロック トレースが見つかりました。

デッドロックが発生しました .... デッドロック情報の出力 グラフ待ち

ノード:1 キー: 5:72057594042384384 (54048e7b3828) CleanCnt:3 モード:X フラグ: 0x0 許可リスト 1: 所有者:0x03D08C40 モード: X フラグ:0x0 参照:0 ライフ:02000000 SPID:62 ECID:0 XactLockInfo: 0x04834274 SPID: 62 ECID: 0 ステートメント タイプ: DELETE 行番号: 1 入力 Buf: 言語イベント: (@P0 nvarchar(4000))delete from part_data where part_id = @P0 要求元: ResType:LockOwner Stype:'OR'Xdes:0x04B511C8 モード: U SPID:60 BatchID:0 ECID:0 TaskProxy:(0x058BE378) 値:0x3d08500 コスト:(0/1296)

ノード:2

キー: 5:72057594042384384 (f903d6d6e0ac) CleanCnt:2 モード:X フラグ: 0x0 許可リスト 0: 所有者:0x03D088A0 モード: X Flg:0x0 Ref:0 ライフ:02000000 SPID:60 ECID:0 XactLockInfo: 0x04B511EC SPID: 60 ECID: 0 ステートメント タイプ: DELETE 行番号: 1 入力 Buf: 言語イベント: (@P0 nvarchar(4000))delete from part_data where part_id = @P0 Requested By: ResType:LockOwner Stype:'OR'Xdes:0x04834250 Mode: U SPID: 62 BatchID:0 ECID:0 TaskProxy:(0x047BA378) 値:0x3d089e0 コスト:(0/4588)

犠牲者リソース所有者: ResType:LockOwner Stype:'OR'Xdes:0x04B511C8 モード: U SPID:60 BatchID:0 ECID:0 TaskProxy:(0x058BE378) 値:0x3d08500 コスト:(0/1296)

SQLServer プロファイラーは、これを 2 つのクライアントが更新 (U) ロックを保持し、排他 (X) ロックにエスカレートしようとしていると示しています。私が読んだ SQLServer のドキュメントでは、ある時点で 1 つのクライアントのみがテーブルを (U) ロックできると書かれているため、なぜトレースに示されている状況が表示されるのか疑問に思っています。

そのトレースで参照されているデータベース オブジェクトは、外部キーのインデックスです。この種の問題を修正した経験のある人がアドバイスを提供できれば、それは大きな助けになるでしょう.

ありがとう、ブラッド。

EDIT は、要求に応じてデッドロック グラフ xml を追加しました。

<deadlock-list>
 <deadlock victim="process989018">
  <process-list>
   <process id="process6aa7a8" taskpriority="0" logused="4844" waitresource="KEY: 5:72057594042384384 (5504bdfb7529)" waittime="9859" ownerId="613553" transactionname="implicit_transaction" lasttranstarted="2009-05-08T11:52:39.137" XDES="0x5fcbc30" lockMode="U" schedulerid="1" kpid="3516" status="suspended" spid="59" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2009-05-08T11:52:39.183" lastbatchcompleted="2009-05-08T11:52:39.183" clientapp="jTDS" hostname="LOIRE" hostpid="123" loginname="sa" isolationlevel="read committed (2)" xactid="613553" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="40" sqlhandle="0x0200000007c76c39efdd8317c6fa7b611b4fd958f05cfcf4">
delete from part_data where part_id =  @P0     </frame>
    </executionStack>
    <inputbuf>(@P0 nvarchar(4000))delete from part_data where part_id = @P0</inputbuf>
   </process>
   <process id="process989018" taskpriority="0" logused="1528" waitresource="KEY: 5:72057594042384384 (5e0405cb0377)" waittime="1250" ownerId="613558" transactionname="implicit_transaction" lasttranstarted="2009-05-08T11:52:39.183" XDES="0x48318f0" lockMode="U" schedulerid="2" kpid="2692" status="suspended" spid="60" sbid="0" ecid="0" priority="0" transcount="2" lastbatchstarted="2009-05-08T11:52:39.183" lastbatchcompleted="2009-05-08T11:52:39.183" clientapp="jTDS" hostname="LOIRE" hostpid="123" loginname="sa" isolationlevel="read committed (2)" xactid="613558" currentdb="5" lockTimeout="4294967295" clientoption1="671088672" clientoption2="128058">
    <executionStack>
     <frame procname="adhoc" line="1" stmtstart="40" sqlhandle="0x0200000007c76c39efdd8317c6fa7b611b4fd958f05cfcf4">
delete from part_data where part_id =  @P0     </frame>
    </executionStack>
    <inputbuf>(@P0 nvarchar(4000))delete from part_data where part_id =  @P0</inputbuf>
   </process>
  </process-list>
  <resource-list>
   <keylock hobtid="72057594042384384" dbid="5" objectname="MESSAGESTOREDB61.dbo.part_data" indexname="idx_part_data_part_id" id="lock3cab740" mode="X" associatedObjectId="72057594042384384">
    <owner-list>
     <owner id="process6aa7a8" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process989018" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
   <keylock hobtid="72057594042384384" dbid="5" objectname="MESSAGESTOREDB61.dbo.part_data" indexname="idx_part_data_part_id" id="lock3cad340" mode="X" associatedObjectId="72057594042384384">
    <owner-list>
     <owner id="process989018" mode="X"/>
    </owner-list>
    <waiter-list>
     <waiter id="process6aa7a8" mode="U" requestType="wait"/>
    </waiter-list>
   </keylock>
  </resource-list>
 </deadlock>
</deadlock-list>
4

7 に答える 7

4

ひどいへようこそ。

前回このような状況に遭遇したのは、更新または削除が、影響している行を分離するのに役立つ適切なインデックスを見つけることができなかったためです。これにより、非カバー インデックスを使用してレコードの位置を変更していたため、不規則なロック エスカレーションが発生しました。

したがって、クエリの一部を分離できる場合は、SQL をチェックして、いくつかのカバー インデックスを提供して実験できないかどうかを確認してください。

カバリング インデックスは、特定の where 句のすべてのフィールドを含むインデックスです。

于 2009-06-11T12:48:41.457 に答える
2

SQLServer でのデッドロックは、ほとんどの場合、1 つのスレッドが 2 つの接続、つまり 2 つのトランザクションを使用して書き込みと読み取りを試行することが原因です。これを機能させたい場合は、1 つの接続を使用して単一のスレッドですべての操作を実行し、実際に接続を再利用していることを確認してください。アプリケーションのレイヤリングが原因で、トランザクション中に読み取りに別の接続を誤って使用しているため、その読み取りが (別の接続を使用して) 他のコードが完了するのを待機している可能性があります。

例(疑似ステップ)

トランスを開始

  • テーブル Foo にデータ (INSERT、UPDATE など) を書き込む
  • 読み取りが終了しないため、別の接続 DEADLOCKを使用して Foo から一部のデータ (テーブル スキャンをトリガーする) を読み取るため、トランザクションはコミットされません。
于 2009-05-08T13:37:10.533 に答える
1

最初はヒントを使用しないでください。通常、SQL Server はそのままにしておいたほうがよいでしょう。

次に、REAL デッドロックが発生していないことを確認します (ただし、デッドロックの外観が示唆するよりもはるかに少ない頻度で発生します)。

第三に、誰かが示唆したように、遅いクエリがあるかどうかを確認して調整します。

私の経験では、顧客がデッドロックの状況を報告するたびに、これが発生したのは、エスカレートする実行速度の遅いクエリがあり、実際にはデッドロックが発生せず、クエリを調整するか、特定のインデックスを追加することで常に問題が解決したためです。

あなたが話している SQL Server のバージョンはわかりませんが、次の各バージョンは以前のものよりも優れたデッドロック管理を備えており、このトピックでは SQL Server 2000 が特に厄介でした。

よろしく
マッシモ

于 2009-11-05T23:44:12.570 に答える
0

何年も前に、1 日あたり 10 億件を超えるトランザクションが対象となっているテーブルで同じ問題に遭遇しました。

1 つの Web サイトのクエリを処理するために、4 つの tomcat サービスがありました。Web サイトのトラフィックが最も少ないときに表示される同じクエリを、2 つの異なるサービスが処理しようとすることがありました。最初のクエリの削除操作は IX をロックしており、同時に実行された 2 番目のクエリは同じことを行っていました。

この問題は、バッファ テーブルを作成することで処理しました。削除アクションはそのテーブルに格納されました。毎秒、SQL ジョブがそのテーブルを読み取り、「削除対象」とタグ付けされた行を削除します。

于 2013-12-27T14:54:09.637 に答える
0

DBCC TRACEON(1222,-1)」および/または「DBCC TRACEON(1204 ,-1)」のようなものを実行したと仮定しています。SQLServer ログのデッドロック トレースを読むのが難しいと思います。排他的 (X) ロックにエスカレートしようとしているのは確かですか?

プロファイラーでトレースを実行し (空のテンプレートを選択)、「デッドロック グラフ イベント」を選択し、表示される新しいタブ (イベント抽出設定) で、それぞれを保存します (「デッドロック XML イベントを個別に保存する」をチェックします)。独自のファイル。このファイルを xml ビューアーで開くと、何が起こっているかを簡単に確認できます。各プロセスは含まれており、プロシージャ/トリガー/etc 呼び出しなどの実行スタックがあり、すべてのロックもそこにあります。col=@value の 2 つの DELETE が問題を引き起こしているとは信じがたいです。実行スタックを見てください。トリガーまたは何か他のことが起こっていますか?

ファイルの「リソース リスト」セクションを確認すると、デッドロックの原因となっている各プロセスによって何がロックされ、保持されているかがわかります。これらのいずれかをロックしない方法を見つければ、デッドロックは解決されます。

于 2009-05-08T13:07:00.560 に答える
0

...デッドロックを回避できるように、UPDLOCKヒントを使用して、問題のテーブルのすべての読み取りを「更新用」に行うことにしました...

...はい、エラーが発生した場合にオブジェクトグラフ全体が削除されるか、そのまま残されるように宣言されたトランザクションがあります。トランザクションには他のデータベース操作はありません。トランザクションが開始される前にいくつかの読み取りが行われますが、トランザクション内では行われません...

トランザクションの外部で読み取りロックをエスカレートする理由を理解しているかどうかはわかりませんが、これは問題を悪化させるだけだと思います。私の経験では、ロックのヒントを先制的に指定すると、良いことよりも害が生じることがわかっています。

そうは言っても…

各トランザクション内で複数の行を削除しようとしていて、SQL がそれぞれのテーブルのロック レベルをエスカレートしているため、デッドロックが発生しているようです。SQL Server の行、キー範囲、およびページ ロックはすべて、すぐにテーブル ロックにエスカレートすることに注意してください。複数の行を削除する複数のトランザクションがある場合、それらはエスカレートしようとし、デッドロックが発生します。

多くのユーザーがいる場合、これによりパフォーマンスが低下しますが、delete ステートメントで TABLOCK ヒントを指定してみて、問題が解決するかどうかを確認してください。

また、SQL ステートメントの実行計画を見て、ロックのエスカレーションがどのように発生しているかを確認してください。

于 2009-07-20T18:36:01.037 に答える
0

まず、2 つの削除ステートメントです。これら 2 つの SPID は同じステートメントを実行しています

delete from part_data where part_id = @P0

おそらく、同じレコードを削除しようとすることはありません。part_dataここでデッドロックが発生します。これは、SQLServer が列を使用してテーブルから行を識別できず、part_id他のレコードもロックしているためです。

したがって、2つのオプションがあります

  1. part_id主キーを作成します(可能な場合)

    また

  2. ステートメントを次のように変更します。(主キーがあると仮定して)

    Select primary_key into #temp From part_data where part_id = @p0

    -- 削除するレコードの主キーを取得します

    delete a from part_data a join #temp b on a.primary_key = b.primary_key

-- 他のレコードをロックせずに、削除するレコードを削除できます

于 2016-11-30T09:24:37.130 に答える