エンジニアのはしがき

プログラミングの日々の知見を書き連ねているブログです

MySQL(InnoDB)のTransaction Isolation Levelsについてまとめる

DBのロックについて考える際にTransaction Isolation Levelsを確認することはよくあると思いますが、バックエンドを触ってない期間が長くなると細かい部分を忘れてしまうのでまとめてみました。

Transaction Isolation Levelsとは

トランザクションが同時に実施された時の一貫性、正確性を定義したもののことで、日本語だとトランザクション分離レベルと呼ばれます。

分離レベルは以下の4つが存在します。

  • SERIALIZABLE
  • REPEATABLE READ
  • READ COMMITTED
  • READ UNCOMMITTED

MySQL固有の概念ではなく他のRDBMS(PostgreSQL, Oracle等)にも存在する概念ですが、RDBMSによって挙動は同一ではないので注意が必要です。

当記事ではMySQL(InnoDB)での挙動をまとめていきます。

読み取り時の問題

分離レベルを理解する前に、データを読み取る際に発生し得る下記の代表的な問題について理解しておく必要があります。

Dirty Read

Fuzzy Read/Non-Repeatable Read

Phantom Read

Transaction Isolation Levels別の挙動

REPEATABLE READ

  • InnoDBのデフォルトの分離レベル。
  • 初回読み取り時にのみスナップショットを確立し、トランザクション内でSELECTする際にそのスナップショットからレコードを参照する。この読み取り方法は「consistent read」と呼ばれる。
    • ただしlocking read(SELECT FOR SHARE, SELECT FOR UPDATE)時は最新のレコードを参照する。
  • スナップショットを参照するため、Dirty Read、Fuzzy Read、Phantom Readが発生しない。
    • 実装時、取得レコードが最新ではないことを考慮する必要がある。

READ COMMITTED

  • 毎回読み取り時にスナップショットを確立し、トランザクション内でSELECTする際はスナップショットからレコードを参照する。
  • コミットされていないレコードは参照しないため、Dirty Readが発生しない。
  • スナップショットが毎回確立される為、Fuzzy Read、Phantom Readは発生する場合がある。
    • 実装時、他トランザクションでのINSERT、UPDATE、DELETEの影響を受け得ることを考慮する必要がある。

READ UNCOMMITTED

  • READ COMMITTEDと同様の挙動だが、加えて「まだCOMMITされていないレコード」も参照する。
  • Dirty Read、Fuzzy Read、Phantom Readが発生する場合がある。
  • トランザクションの変更による影響でデータの不整合を起こす可能性が高いが、パフォーマンスは高い。
  • 一貫性の無いレコードが取得されることを許容できる要件なら使える。

SERIALIZABLE

  • システム変数のautocommitの値によって挙動が異なる。
    • autocommitが0(disabled)のとき
      • SELECTは暗黙的にSELECT FOR SHAREに変換して実行される。
      • 共有ロックがかかることを考慮しての実装が必要になる。
    • autocommitが1(enabled)のとき
  • Dirty Read、Fuzzy Read、Phantom Readが発生しない。
  • トランザクションのコミットを確実に取得したい場合に使える。ただしパフォーマンスが犠牲になる点は注意が必要。

MySQL :: MySQL 8.0 Reference Manual :: 5.1.8 Server System Variables

Transaction Isolation Levelsを変更する方法

システム変数から変える

システム変数のtransaction_isolationトランザクション分離レベルを指定できます。 my.cnfなどのオプションファイルに追記するのが良いと思います。

MySQL :: MySQL 8.0 Reference Manual :: 5.1.8 Server System Variables

MySQL :: MySQL 8.0 Reference Manual :: 4.2.2.2 Using Option Files

SQL文から変える

SET [GLOBAL | SESSION] TRANSACTION
    transaction_characteristic [, transaction_characteristic] ...

transaction_characteristicにトランザクション分離レベルを指定します。

MySQL :: MySQL 8.0 Reference Manual :: 13.3.7 SET TRANSACTION Statement

あとがき

Transaction Isolation Levelsはどれがおススメという話ではなく、それぞれの特性を理解した上で要件によって適切に採択するのが良さそうです。

参考

MySQL :: MySQL 8.0 Reference Manual :: 15.7.2.1 Transaction Isolation Levels