ltmemo

トランザクション分離レベルとロックについて勉強した

tags:
2022-03-20

ToC

なにを学ぶか

transaction分離レベル、およびそれを実現するlockの挙動について知見を深めたい

分離レベルと、それぞれどういう読み取りが起きるのかまではわかったが、
InnoDBではphantom readが起きないというのを見かけて詳しく知りたくなった
lockの挙動を覚えることで、デッドロックが発生したときの原因調査ができるようになってほしい

参考文献が非常に参考になったので、後は実務でぶつかったら都度確認して対応みたいな感じでよいかもしれない

transaction分離レベル

transaction分離レベルはSQL標準で定められたもので、以下の四つがある

  • read uncommited

    • 分離レベルが一番弱い。ダーティリード、ファジーリード、ファントムリードが起きる
  • read commited

    • ファジーリード、ファントムリードが起きる。Postgresのデフォルトはこれ
  • repeatable read

    • ファントムリードが起きる。MySQL(というかInnoDB?)のデフォルトはこれ
    • ただしInnoDBではファントムリードを防ぐようになっている
      • MVCC(Multi version concurrency control)という仕組みで何とかしているらしい
        • lock取得時のsnapshotから読み取りをするので、ファントムリードが起きないそうだ
  • serializable

    • 各種リード現象は起きないが、性能が低い
  • ダーティリード

    • 他transactionの、未コミットの内容が見える
  • ファジーリード

    • 他transactionのcommit済みの更新・削除したデータが見える
      • 読み取りを行うたびに結果が変わる可能性がある現象
  • ファントムリード

    • 他transactionのcommit済みの挿入されたデータが見える
      • 読み取りを行うたびに結果が変わる可能性がある現象

このほかロストアップデートと言って、先行transactionの更新内容を後続のtransactionが上書きしてしまう挙動もあるらしい

ACID特性

  • Atomicity
    • タスクがall or nothingであること(すべて実行されるもしくはまったく実行されない)
  • Consistency
    • 整合性を満たす
  • Isolation
    • 操作の過程が他の操作から隠蔽される
  • Durability
    • 完了がユーザに通知されたタイミングで操作が永続的になり結果が失われないこと

InnoDBのREPEATABLE READのlock

ハマりどころがあるようだ
lockを獲得する読み取りが、ロストアップデートに対応するために、REPEATABLE READな挙動にならないらしい

どうやらlockしている行を参照しようとするとlock解除まで待ち、その後最新の値を取得するようだ
これはREPEATABLE READが本来保障する挙動になっていない(値が変わってはいけないので)

この挙動、lock for updateでselectかけるにしか起きないらしい。ややこしいな
locking readはread commited相当の挙動になると覚えるのがよい?

transaction開始直後にlocking readするなど、特定の状況では意識したほうが良いらしい(今の知識じゃ出来る気しないけど...)

行ロック

indexの有無でlockの挙動が変わるとか聞いた

  • レコードロック
    • インデックスレコードのロック
  • ギャップロック
    • インデックスレコードの間のギャップのロック
    • もしくは、インデックスレコードの先頭の前、末尾の後のギャップのロック
    • indexの対象カラムに、50,51,100のレコードがそれぞれあるとき、100のレコードをfor updateでlockすると
      51と100の間にはinsertできない。51より前はできる。100以上はできない、となる
    • 複合indexの場合はもうちょいややこしそう
    • primary key, unique keyの場合は、対象が一意に定まるので、そのレコードがあればそれだけlockする形になり、ギャップロックは発生しない
  • ネクストキーロック
    • インデックスレコードに対するレコードロックと、その前にあるギャップに対するギャップロックの組み合わせ

メモ

  • lock取得は、排他ロックはfor update、共有ロックはlock in share mode

参考文献

  • https://github.com/ichirin2501/doc/blob/master/innodb.md#%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3%E5%88%86%E9%9B%A2%E3%83%AC%E3%83%99%E3%83%AB
  • https://techblog.kayac.com/repeatable_read.html
  • http://nippondanji.blogspot.com/2013/12/innodbrepeatable-readlocking-read.html

最終更新: 2022-03-20