Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
16
Help us understand the problem. What is going on with this article?

More than 3 years have passed since last update.

@noonworks

InnoDBのロックに関する用語の確認

ロックの分類

InnoDBのロックは「タイプ1」「モード」「精密なモード2」で分類できる。

ロックのタイプ1(lock type)

ロックのタイプは2種類ある。InnoDBに限った概念ではない。
InnoDBではなるべくテーブルロックを使わず、行ロックを使うようにしているそうだ。実際、明示的にテーブルロックを利用しようという場面はほとんどないと思う。

たまに勘違いしている人をみかけるが、「行ロックの範囲がテーブル全体である」ことと「テーブルロック」は異なる。前者はあくまでも行ロックである。

システムによっては、メモリ節約のために「大量の行ロック」を「テーブルロック」に自動的に変更することもあるらしいが、InnoDBでは不要だそうだ。(参考:ロックのエスカレーション

また、InnoDBでは、行ロックだけを使っているつもりでも内部的にはテーブルロックの仕組みが使われている。(詳しくはインテンションロックの項目を参照。)

ロックのモードlock mode

ロックのモードは2種類ある。InnoDBに限った概念ではない。
共有ロックは(S)、排他ロックは(X)と表記されることがある。

ロックの精密なモード2(precise mode)

ロックの精密なモードは、InnoDBに特有の概念(というより、実装方法からくる分類)。行ロックだけの分類で、テーブルロックには関係ない。

  • レコードロックは、その名の通り、レコードをロックする。
  • ギャップロックは、その名の通り、ギャップ(隙間)をロックする。レコードとレコードの間をロックすることで、その空間に新しいレコードが挿入されることを防ぐ。
  • ネクストキーロックは、レコードロックと、そのレコードの前の空間に対するギャップロックをセットにしたロック。

先頭のレコードより前、末尾のレコードより後

それぞれ、先頭レコードよりも前にある疑似レコードと、末尾レコードより後にある疑似レコードを意味する。「先頭レコードより前」や「末尾レコードより後」のギャップロックを表現するために使われる。
日本語の方はあまり使わないと思う。

先頭レコードより前への挿入をブロックするには、先頭レコードとinfimumレコードのギャップをロックする必要がある。
また、末尾レコードより後ろへの挿入をブロックするには、末尾レコードとsupremumレコードのギャップをロックする必要がある。

「先頭レコードのネクストキーロック」を使えば「先頭レコードとinfimumのギャップ」もロックされる。そのため、infimumは実際にはあまり出番がないようだ。

しかし、「末尾レコードのネクストキーロック」では「末尾レコードとsupremumレコードのギャップ」をロックすることはできない。そのため、innodb_lock_monitorで見るとsupremumの表示はよくある。

インテンションロックintention lock

テーブルに対するロックで、これにも2種類のモードがある。

  • インテンション共有ロック(intention shared lock):(IS)と表記される
  • インテンション排他ロック(intention exclusive lock):(IX)と表記される

インテンションロックは、行ロックとテーブルロックを共存させるための実装上の都合で存在するロック。

動作としては、トランザクションTx1がテーブルtest上で行ロック(X)を取得しようとする場合、先にテーブルtestに対するテーブルロック(IX)の取得を試みる。(同様に、行ロック(S)を取得しようとする場合ならば、テーブルロック(IS)を試みる。)

このとき、テーブルtest他のセッションですでにLOCK TABLES test READ;で明示的にテーブルロック(S)されていたとする。すると、テーブルロック(S)とテーブルロック(IX)は競合するので、Tx1はテーブルロック(IX)を取得できない。よって、Tx1は行ロック(X)も取得できない。
これにより、テーブルロック済みのテーブル上のレコードに対する、競合する行ロックの取得を防げる。

別のケースとして、他のトランザクションTx2がテーブルtest上で行ロック(S)を取得していたとする。つまり、Tx2はテーブルtestに対するテーブルロック(IS)を取得済みということになる。この場合、テーブルロック(IS)とテーブルロック(IX)は競合しないので、Tx1もテーブルロック(IX)を取得できる。
その後、Tx1は、Tx2が行ロック(S)していないレコードの範囲についてならば、行ロック(X)を取得できるだろう。

このように、行ロック時にもテーブルロックを使用して2段階にすることで、テーブルロックと行ロックを解りやすく共存できるようにしている。

MySQL :: MySQL 5.6 リファレンスマニュアル :: 14.2.3 InnoDB のロックモードより、ロックの対応表を引用

X IX S IS
X 競合 競合 競合 競合
IX 競合 互換 競合 互換
S 競合 競合 互換 互換
IS 競合 互換 互換 互換
  • インテンション同士は(共有・排他を問わず)競合しない
  • 共有同士は(インテンションかどうかを問わず)競合しない

脚注


  1. ドキュメントにはない表記。InnoDBのソース上のLOCK_TABLE定数とLOCK_REC定数の定義してあるところにコメントで/** Lock types */と書いてあったため、また、「ロックがLOCK_TABLELOCK_RECか返す関数」がlock_get_type_lowだったため、こう呼んでいる。 

  2. ドキュメントにはない表記。InnoDBのソース上のLOCK_GAPLOCK_REC_NOT_GAPが定義してあるところにコメントでPrecise modesと書いてあったため、こう呼んでいる。 

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
16
Help us understand the problem. What is going on with this article?