Help us understand the problem. What is going on with this article?

[RDBMS][SQL]トランザクション分離レベルについて極力分かりやすく解説

More than 1 year has passed since last update.

技術系の記事色んなところで書いてたけど、ここにまとめることにした。昔書いてたやつは綺麗バッサリ消そうかと思ったんだけど、やたらView数が多いやつが何個かあったので気が向いた時に乗り換えしつつ(予定)今の知識で更新。

概要

以下の3つの不都合な読み込み現象がある。この意味に関しては後ほど解説。とりあえずはどれもRDBMSのACID特性のI(Isolation-隔離性)から外れたものと思ってくれればいい。

  • ダーティリード
  • ファジーリード(非再現リード,ノンリピータブルリード)
  • ファントムリード

で、本題のトランザクション分離レベルは4つのレベルがある。

  • READ UNCOMMITTED
  • READ COMMITTED
  • REPEATABLE READ
  • SERIALIZABLE

下に行くほど高レベルで上に行くほど低レベル。
高レベルになればなるほど、先ほどの不都合な読み込み現象が発生しなくなる。が、代わりにパフォーマンスが落ちる。

つまり、「パフォーマンスを上げるためにある程度の読み込み不都合を妥協するか、パフォーマンスを落としてもいいから不都合を発生しないようにするか」という設定のレベルのことを言う。

読み込みの不都合

先述した3種類の読み込み不都合に関して説明。
まずこれ知らないと分離レベルの話できない。

ダーティリード

別のトランザクションでコミットされてないデータが読み取れる現象。

  1. トランザクションAでレコードを①から②にUPDATE(未コミット)
  2. トランザクションBでレコードをSELECTする
  3. トランザクションAをロールバックする
  4. トランザクションBで取得したデータは②となっている。

一番低いレベルでないと発生しない。これを許容するシステムをまだ見たことがない・・・

ファジーリード(非再現リード,ノンリピータブルリード)

別のトランザクションで更新されたデータを読むことにより、一貫性がなくなる現象。

  1. トランザクションAでレコードをSELECTする。①となっている。
  2. トランザクションBでレコードを①から②にUPDATEし、COMMITする。
  3. トランザクションAで同じレコードを再度SELECTする。②となっている。

トランザクション分離レベル知る前はそういうもんじゃんとか思っていたんだけど、
2つのトランザクションが隔離されてないので使ってる側で気にしないといけない。
その時点で隔離性から離れてるんだよね。

ファントムリード

別のトランザクションで挿入されたデータが見えることにより、一貫性がなくなる現象。

  1. トランザクションAでレコードをSELECTする。該当レコードがない。
  2. トランザクションBでレコードをINSERTし、COMMITする。
  3. トランザクションAでレコードをSELECTする。2でINSERTとしたレコードが取得できる。

ファジーリードとよく似ているがINSERTとUPDATEという点が違う。
また、以下もファントムリードとなる。

  1. トランザクションAでレコードをCOUNTする。X件取得できた。
  2. トランザクションBでレコードをINSERTし、COMMITする。
  3. トランザクションAでレコードをCOUNTする。X+1件取得できた。

以上が読み込みにおける3種類の不都合の簡単な説明となる。

トランザクション分離レベルと読み込みの不都合の関係

簡潔に以下のような関係性となる。

ダーティリード ファジーリード ファントムリード
READ UNCOMMITTED 発生する 発生する 発生する
READ COMMITTED 発生する 発生する
REPEATABLE READ 発生する
SERIALIZABLE

こうしてみると隔離性の高いSERIALIZABLEをいつも選択がいいのではないかと思ってしまうが、隔離性の高さ故の問題もある。が、今回は極力分かりやすくというコンセプトなので説明では省略

幾つか補足

  • あくまで「発生しないことが保証されている」というもので、レベル低いからと言って発生するようになっているかと言えばそうとは限らない。その辺りの実装はRDBMSによって大きく違い、例えばMySQLではREPEATABLE READであってもファントムリードは発生しない。 (が、代わりに別の問題があるのだけど今回はスルー)
  • 標準SQLで「発生しないことが保証されている」というものなので、発生しない為にどういう方法を取るかというのはRDBMS毎に違う。発生する状況になったらエラーになる、トランザクション完了を待つ等。
  • RDBMSによってデフォルトのトランザクション分離レベルが違う。対応している分離レベルの種類も違う。

デフォルトのトランザクション分離レベル

  • MySQL(InnoDB) … REPEATABLE READ
  • PostgreSQL … READ COMMITTED
  • Oracle … READ COMMITTED
  • SQL Server … READ COMMITTED

どうでもいい話

元記事書いたの4年前だった。

PruneMazui
試行錯誤の毎日 割と雑食だけどよくいるのはこの辺 ⇒ アジャイル / プロジェクトマネジメント / バックエンドアーキテクチャ / OOP / FP / RDBMS
admin-guild
「Webサービスの運営に必要なあらゆる知見」を共有できる場として作られた、運営者のためのコミュニティです。
https://admin-guild.slack.com
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
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  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
ユーザーは見つかりませんでした