2

私は 2 つの SPID をトランザクションとして実行しています。以下は、それぞれがとりわけ行うことです。

SPID A -

  1. テーブル 1 の行 1 ~ 10 を更新します
  2. .......

SPID B -

  1. テーブル 1 の行 5 を更新します
  2. テーブル 1 から行 4、5、および 6 を選択し、テーブル 2 の行を更新します。
  3. ……
  4. ……

SPID A が行 4 を更新し、クラスター化インデックスの X ロックを待って行 5 を更新し、SPID B が手順 2 で、X にある行 4 のクラスター化インデックスの S ロックを待機しているデッドロック シナリオに直面しています。 SPID A によるロック。テーブル 1 にも非クラスター化インデックスがありますが、選択クエリをカバーしていないため、クラスター化インデックスを検索します。私はそれをカバリング インデックスにしても、SPID A は非クラスター化インデックスのロックを保持し、SPID B を待機させると想定しています。SPID Bが行5への更新をすでに開始している場合、多かれ少なかれテーブル全体を更新しているSPID Aがロックを取得するのを待たなければならないように、分離レベルをシリアライゼーションにエスカレートすることを検討しています。また、SPID Bを防ぎますSPID A が既に開始されている場合は、x ロックを取得できません。

この行き詰まりを解消するために、他に何か提案はありますか? ありがとう。

4

1 に答える 1

0

このブログエントリをご覧ください。これには、現在存在するロックを表示するための便利なSQL スクリプトが含まれており、それらに関するすべての情報が表示されます。

SELECT
db.name DBName,
tl.request_session_id,
wt.blocking_session_id,
OBJECT_NAME(p.OBJECT_ID) BlockedObjectName,
tl.resource_type,
h1.TEXT AS RequestingText,
h2.TEXT AS BlockingTest,
tl.request_mode
FROM sys.dm_tran_locks AS tl
INNER JOIN sys.databases db ON db.database_id = tl.resource_database_id
INNER JOIN sys.dm_os_waiting_tasks AS wt ON tl.lock_owner_address = wt.resource_address
INNER JOIN sys.partitions AS p ON p.hobt_id = tl.resource_associated_entity_id
INNER JOIN sys.dm_exec_connections ec1 ON ec1.session_id = tl.request_session_id
INNER JOIN sys.dm_exec_connections ec2 ON ec2.session_id = wt.blocking_session_id
CROSS APPLY sys.dm_exec_sql_text(ec1.most_recent_sql_handle) AS h1
CROSS APPLY sys.dm_exec_sql_text(ec2.most_recent_sql_handle) AS h2
GO

一般的に、私の推測では、SQL Server は既定で (すべての SQL Server のように) PAGE ロックを使用しており、このようにして単一の行を更新すると、同じ PAGE のすべての行がブロックされる可能性があります。SQL サーバーでのロックの理解を深めるには、この記事を参照してください。また、楽しみのためにこのブログを参照してください。ブログでは、オラクルの後で奇妙になる可能性があること、select が update をブロックできることを説明していますが、これは SQL サーバーで可能です。

問題を回避するには、 update でROWLOCKヒントを使用します。パフォーマンスが少し低下し、デッドロックも発生します。2 番目の解決策は、SQL サーバーでデッドロック検出タイムアウトを低く設定し、SQL サーバー エラーをキャッチして、デッドロックの被害者エラーである場合は再試行することです。

于 2012-10-21T18:54:17.133 に答える