innodbのロック機構について
今更ながら innodb のロック機構でややこしいところをまとめてみた。
ネクストキーロック
- ネクストキーロックはあくまで、あるプライマリインデックスレコードに対するレコードロックとその前にあるギャップへのギャップロックの組み合わせ
- あるプライマリインデックスレコードの次のレコードに対するレコードロックのことを呼ぶのではない
- まず、innodb では走査されたインデックスレコードに対してレコードロックがかかる
- range 検索 においては、右端値の次の値まで走査がかかるので、実際にヒットしたレコードの次のレコードまでネクストキーロックがかかる
- unique key かつ <= 指定なら次のレコードまで走査する必要は本来ないのだが、実装の複雑化を避けるためそうなっているに違いない!
- これをネクストキーロックと呼ぶ人も多い
repeatable read における DML 別ロック種別
- SELECT
- lock はなし trx 単位での MVCC
- lock in share mode
- 共有ネクストキーロック
- update/delete/select for update
- 排他ネクストキーロック
ただしここでネクストキーロックと言っているのは、where 句で実際に走査されたタイプによって異なる
- 例えば空振りなしの等価検索なら、合致したレコードのみのレコードロックがかかる
- 空振りありの等価検索なら、その値の次に存在するレコードの前のギャップロック
- range 検索なら 合致したレコードのネクストキーロック(左端と値が一致しているレコードに関しては、レコードロックのみ)+range の右端の次に存在するレコードのネクストキーロック
挿入インテンションギャップロック
- insert 文の実行時に取得される特殊なギャップロック
- そもそも、正常系において insert は常に存在しない key に対して行われるので、取得されるロックは常にギャップロックとなる
- select for update の空振り等価検索とかと同じ
- 追加する key に unique 制約がかかっている場合、ギャップロックとはいえギャップだけではなく自身が追加しようとしている key 値に対するレコードロックも暗黙的にとっている
- そもそも、正常系において insert は常に存在しない key に対して行われるので、取得されるロックは常にギャップロックとなる
- 挿入インテンションギャップロック自体は競合しないので、同じギャップへの insert は wait が起きない
- 一方で、普通の排他ギャップロック(例えば、select for update の空振り等価検索だったり delete の range 絞り込みにおけるネクストキーロックのギャップ分だったり)とは競合する
- また、追加しようとしている key 値に対するレコードロックに関しては普通に競合する
- そうしないと unique 制約が守れないしね