web-dev-qa-db-ja.com

SELECTクエリのデッドロックを防ぐ方法は?

マルチセッションDBを持っています。多くの行をDBに挿入するセッションはほとんどありません。 1つのセッションがこのテーブルから選択します。

SELECTクエリでデッドロックが発生することがあり、その理由がわかりません。

次に例を示します。

Create Table t1([id] int identity(1,1), [column] varchar(max))

挿入は次のようになります:(「後」のトリガーから実行しています)

Begin Transaction
Insert into t1 WITH (TABLOCKX) ([column]) values ('value 1'), ('value 2') ... ('value N')
Commit Transaction

選択は次のようになります。

Select TOP 10 [id],[column] from t1 order by id

挿入に対するロックは、セッション挿入のシーケンスをDBに保持することを目的としています。

トランザクションで1つのテーブルのみをロックするたび。 1つのセッションを挿入し、2番目のセッションを選択してデッドロックを回復しようとしましたが、失敗しました。 TABLOCKXを追加する前は、デッドロックは発生していません。

だから私の質問は:

  1. どうしてデッドロックが発生するのですか? (おそらくネストされたトランザクションにありますか?)
  2. 選択をブロックしない方法で書き込みロックを行うオプションはMSSQLにありますか?
  3. デッドロックを防ぐためのアイデアはありますか? (ただし、セッション挿入シーケンスを変更せずにDBに保持します...)
3
SHR

クエリやデッドロックグラフなしでは、デッドロックについて多くを語ることはできません。
排他的なテーブルロックを指定する理由はありますか?
SQL Serverは、行またはページからテーブル自体へのロックのエスカレーションに優れています。

選択をブロックしない方法で書き込みロックを行うオプションはMSSQLにありますか?

はい、あります READ COMMITTED SNAPSHOT ISOLATION LEVEL を有効にできます。
この分離レベルを使用すると、コミットされた内容をいつでも読み取ることができます。その時点で別のクエリが書き込んでいる場合は、書き込まれた内容の最新のスナップショットが表示されます。
MSDNページを読んで、RCSILがアプリで機能するかどうかを確認してください。

6
DrTrunks Bell