2012年12月9日日曜日

SQLSERVER デットロックを防ぐ

2つのセッションが1つのテーブルにアクセスするとき、異なる抽出条件に
なっているにも関わらず、そこでデットロックが発生することはないだろうか?

■状況
たとえば、テーブルのカラムが
ID
GROUP
NAME
AGE
となっていて、

セッション①
WHERE ID = 1

セッション②
WHERE ID = 2

などとアクセスする。
このとき、別のデータを取得しようとしているので、ぶつからないはずである。

■原因
いくつかあるのだが、以下のような場合である。

①ID、GROUPのカラムで複合一意キーを指定していたが、どちらか片方で
 アクセスしていた。

②一意キー以外の条件でアクセスすると、関係ないレコードまでロックされる
 (SQLSERVERは、勝手に広範囲をロックしてしまうようだ)

■対応策

①複合一意キーの場合は、その定義順序で、定義されているカラムを必ず指定すること

② 一意キー以外の条件でアクセスする場合、WITH (NOLOCK) オプションでまず
 データを取得する。その後、取得結果をカーソルでまわしながら、一意キーで
 再度SELECTする。
 ※ WITH (NOLOCK) オプションは、ROLLBACK時の影響があることから乱用は避けたい

このような対応で、ロック範囲は意図した通りとなり、デットロックは軽減される。

■参考

ロック範囲が意図した範囲か確認する方法として、以下がある。

「Management Studio」を2つ起動させておく。

①片方で、範囲外と思われるレコードをUPDATE

②もう片方で、確認したいSELECT文を流す( 調べたいWHERE句を指定して )

以上を実行してみて、固まる(ロック待ち)となれば、ぶつかっているし、
無事にSELECTできれば、ロック範囲は重なっていない。




0 件のコメント:

コメントを投稿