- PR -

SQLSERVERのデッドロックについて

1
投稿者投稿内容
だいご
会議室デビュー日: 2007/09/24
投稿数: 17
投稿日時: 2007-11-14 13:13

VisualStudio2003のC#(.NET1.1)で作成したPC上で動作するWindows.Formを
もつプログラム(Webプログラムではない)があります。
デザイナで SqlDataAdapter を作成し、SelectCommandだけを定義して
DataSet と SqlConnection を作成しました。
SelectCommand の SQL文は、複数のテーブルをJOINした程度の簡単な
抽出SQLで、特に難しい構文は使用してません。
接続先のDBはSQLServer2000(SP3a)で、SqlDataAdapterのFill()メソッドを
使用して SelectCommandを実行します。
このプログラムを実行すると稀になんですが、

トランザクション(プロセス ID xx)が、lockリソースでほかのプロセスと
デッドロックしました。トランザクションがデッドロックの対象として選択
されています。トランザクションを再実行してください。

という例外が発生する事があります。

確かに他の沢山のPCから、上記の同じプログラムや別のプログラムから
SELECT/INSERT/UPDATE/DELETE などの SQLを上記の対象テーブルに行いますが、
上記プログラムは、トランザクションを定義していない、ただの SELECT文
です。

なぜ、デッドロックが発生するのか、
色々調べてみたのですが判りませんでした。

同じ様な現象をご存知の方、または、原因をご存知の方は
いらっしゃいませんでしょうか?
Jitta
ぬし
会議室デビュー日: 2002/07/05
投稿数: 6267
お住まい・勤務地: 兵庫県・海手
投稿日時: 2007-11-14 22:13
 デッドロックとは何かを、理解されているでしょうか。
どのようなときに、どのような理由で発生するか、ご存じでしょうか。
その理解がなければ、どんなに調べてもわからないと思います。


 とりあえず、データ操作が「開く→操作→閉じる」となっているか、確認してください。開きっぱなしで、他の操作のために二重三重に開いていないか、特に確認してください。
unibon
ぬし
会議室デビュー日: 2002/08/22
投稿数: 1532
お住まい・勤務地: 美人谷        良回答(20pt)
投稿日時: 2007-11-14 22:26
パラレルワールドをワームホールでつないでおきます。
http://www.atmarkit.co.jp/bbs/phpBB/viewtopic.php?topic=42240&forum=26
だいご
会議室デビュー日: 2007/09/24
投稿数: 17
投稿日時: 2007-11-15 11:04

Jittaさん。
コメントありがとうございます。

>  デッドロックとは何かを、理解されているでしょうか。
> どのようなときに、どのような理由で発生するか、ご存じでしょうか。
> その理解がなければ、どんなに調べてもわからないと思います。

そうですね。すみません。
SQL Serverのデッドロックに関しては、サイクルデッドロックと、変換デッドロック
の2種類存在する、という位しか判りません。
しかしこの2種類のデッドロックに関しての資料や記事を探してみると、
必ず1トランザクション内(トランザクションの開始からコミットを発行するまでの間)で
UPDATE等の更新SQLを発行した場合に発生する、という書き方になっています。
SELECTのみの場合(ロックヒント等は使ってません)は、共有ロックがかかりますが、
共有ロックは複数のプロセスから重ねてかける事ができるんですよね(自信ありませんが)。
他のプロセスがUPDATE等の更新SQLを発行したとしても、自分はSELECTのみなので、
自分のトランザクションの分離レベルによって、ダーティリードするか、待たされるか
のどちらかだと思うのですが、違うのですか?


> とりあえず、データ操作が「開く→操作→閉じる」となっているか、確認してください。
> 開きっぱなしで、他の操作のために二重三重に開いていないか、特に確認してください。

はい。
C#のSqlDataAdapterのFill()メソッドは、DBへの接続を明示的にしていない場合は
Fill()メソッドの中で接続し、SELECTし、接続をクローズする、の一連の流れを自動で
行います。問題にしているプログラムでは、他の接続やSQLの発行は行いません。
囚人
ぬし
会議室デビュー日: 2005/08/13
投稿数: 1019
投稿日時: 2007-11-15 11:33
その Select しかしていないというトランザクションを「トランザクションA」とします。
更新をしているトランザクションを「トランザクションB」とします。

分離レベルが明言されていませんが、トランザクションA の分離レベルは REPEATABLE READ 以上の強度だとします。

1. トランザクションA が Table1 を Select する。(Select したレコードに共有ロック)
2. トランザクションB が Table2 を Update する。(Update したレコードに排他ロック)
3. トランザクションB が Table1 を Update する。(1 で 共有ロック中のレコードを Update しようとして待ち)
4. トランザクションA が Table2 を Select する。(2 で 排他ロック中のレコードを Select しようとして待ち)
5. デッドロック発生。とりあえずトランザクションAを殺す。


Select しかしていないというその処理、トランザクションにしているんですよね?
何をロールバックしたいのでしょうか?


#質問が2箇所にあって両方見るのメドクサイんで、向こうの流れは見ていません。
_________________
囚人のジレンマな日々
だいご
会議室デビュー日: 2007/09/24
投稿数: 17
投稿日時: 2007-11-15 12:49

囚人さん
こんな質問に対して、コメントありがとうございます。

> Select しかしていないというその処理、トランザクションに
> しているんですよね?

すみません。一番初めの投稿に書きもれてますが、
SqlDataAdapterのFill()メソッドを実行する前に、トランザクションの
作成や設定は行っておりません。ですので、実際にFill()メソッドの中で
どんな分離レベルで動いているのか判らないんです。デバッガで覗いても、
それらしき情報が判らないんです。
調べる方法があるのでしょうか?


> 1. トランザクションA が Table1 を Select する。(Select したレコードに共有ロック)
> 2. トランザクションB が Table2 を Update する。(Update したレコードに排他ロック)
> 3. トランザクションB が Table1 を Update する。(1 で 共有ロック中のレコードを Update しようとして待ち)
> 4. トランザクションA が Table2 を Select する。(2 で 排他ロック中のレコードを Select しようとして待ち)
> 5. デッドロック発生。とりあえずトランザクションAを殺す。

この場合、トランザクションAは、トランザクション内で2回 SELECTを発行してますが、
1回でもデッドロックは起こりますか?
1

スキルアップ/キャリアアップ(JOB@IT)