2009年9月 1日

[mysql 15005] 1行も削除されないDELETE文によるロック

こんばんは。ごとうと申します。

INNODBで下の様な主キーが複合のテーブルに対して、
・第1キーを指定して一括DELETE
・同じ第1キーで複数件INSERT
という処理を1トランザクションで行おうとしています。

--

CREATE TABLE test
(
a INT NOT NULL,
b INT NOT NULL,

PRIMARY KEY (a, b)
) TYPE = INNODB;

BEGIN;
DELETE FROM test WHERE a = 1;

INSERT INTO test (a, b) VALUES (1, 1);
INSERT INTO test (a, b) VALUES (1, 2);
...
COMMIT;
--

この処理が↓のような順番で2接続で同時に実行されたとき、デッドロックしました。

--
接続1> BEGIN;
接続1> DELETE FROM test WHERE a = 1; <-- 該当行なし

接続2> BEGIN;
接続2> DELETE FROM test WHERE a = 2; <-- 該当行なし
接続2> INSERT INTO test (a, b) VALUES (2, 1); <-- ブロックされる

接続1> INSERT INTO test (a, b) VALUES (1, 1); <-- デッドロック
ERROR 1213 (40001): Deadlock found when trying to get lock; try
restarting transaction
--

詳しく調べたところ、上の両方のDELETEで1行も削除されなかったときだけ
(テーブルが空だった場合など)デッドロックが発生するようでした。
接続1は a=1 のみ処理し、接続2は a=2 のみ処理しているので問題ないように思うのですが・・・

ひとまず、DELETEの前に SELECT 〜 FOR UPDATE で行が存在するかを確認するようにすると
デッドロックはしなくなりましたが、上記のような「一括削除→複数挿入」の
処理をする場合、どのようにするのが一般的でしょうか?

また、色々実験してみたところ、
↓の様な、主キーが一つだけのテーブルでも同じ現象が発生しました。

--
CREATE TABLE test
(
id INT NOT NULL,
PRIMARY KEY (id)
) TYPE = INNODB;

接続1> BEGIN;
接続1> DELETE FROM test WHERE id = 1; <-- 該当行なし

接続2> BEGIN;
接続2> DELETE FROM test WHERE id = 2; <-- 該当行なし
接続2> INSERT INTO test VALUES (2); <-- ブロックされる

接続1> INSERT INTO test VALUES (1); <-- デッドロック
ERROR 1213 (40001): Deadlock found when trying to get lock; try
restarting transaction
--

これも削除される行があればデッドロックはしなかったので、
DELETE文で削除される行がある場合は、その行のみロックされ、
削除される行が無い場合はそのテーブル全体へのINSERTがブロックされる
ような気がするのですが、そういうものなのでしょうか?


MySQLのバージョンは「5.0.51a」と「5.1.32」で試しています。
トランザクション隔離レベルは最初デフォルトの「REPEATABLE READ」で試していましたが、
「READ UNCOMMITTED」でも同じ結果になりました。

よろしくお願いします。


投稿者 xml-rpc : 2009年9月 1日 00:53
役に立ちました?:
過去のフィードバック 平均:(0) 総合:(0) 投票回数:(0)
本記事へのTrackback: http://hoop.euqset.org/blog/mt-tb2006.cgi/88153
トラックバック
コメント
コメントする




画像の中に見える文字を入力してください。