特定のキーでレコードを削除し、新しいレコードを挿入する必要があるテーブルのセットがあります。キーごとに異なるトランザクションが使用されます。
トランザクション1:
DELETE FROM table1 WHERE id=1; -- many records
DELETE FROM table2 WHERE id=1; -- many records
INSERT INTO table1 VALUES (1,...),...; -- many records
INSERT INTO table2 VALUES (1,...),...; -- many records
トランザクション2:
DELETE FROM table1 WHERE id=2; -- many records
DELETE FROM table2 WHERE id=2; -- many records
INSERT INTO table1 VALUES (2,...),...; -- many records
INSERT INTO table2 VALUES (2,...),...; -- many records
2つのトランザクションが同時に実行されていると、そのうちの1つでロック待機タイムアウト超過エラーが発生します。両方のテーブルのIDにはインデックスが付けられているため、行ベースのロックである必要がありますが、なぜこのエラーが発生するのですか?
InnoDBテーブルの使用。
例の「1」と「2」のように、「id」の値が隣接している場合、それらは隣接していないが、その間に値を持つインデックス内に行がない場合を含め、 「行」ロックの一部であるインデックスギャップロックにぶつかっています。
InnoDBは、テーブルインデックスを検索またはスキャンするときに、検出したインデックスレコードに共有ロックまたは排他ロックを設定するように、行レベルのロックを実行します。したがって、行レベルのロックは実際にはインデックスレコードロックです。さらに、インデックスレコードの次のキーロックは、そのインデックスレコードの前の「ギャップ」にも影響します。つまり、次のキーロックは、インデックスレコードロックに加えて、インデックスレコードの前のギャップに対するギャップロックです。あるセッションがインデックス内のレコードRに共有ロックまたは排他ロックを持っている場合、別のセッションは、インデックス順にRの直前のギャップに新しいインデックスレコードを挿入できません。
— http://dev.mysql.com/doc/refman/5.6/en/innodb-record-level-locks.html
そのページが示唆するように、トランザクション分離レベルREAD COMMITTED
は、それが使用しているものではなく、ギャップロックが問題である場合に役立つことがあります。
また、挿入の主キーの競合である可能性もあります。
INNODB_LOCKS
と INNODB_LOCK_WAITS
information_schema
のテーブルは、追加の診断情報を提供する場合があります SHOW ENGINE INNODB STATUS;
不可解な場合もあります。