この記事には広告を含む場合があります。
記事内で紹介する商品を購入することで、当サイトに売り上げの一部が還元されることがあります。
こんにちは、ほろよい(@horoyoi_blog)です
今回はプログラミング初心者に向けて、トランザクションの分離レベルについてお話しします
- トランザクションの分離レベルって何?
- 分離レベルが違うと何がどうなるの?
そのような疑問をお持ちの方は是非参考にしてください!
簡潔に分かりやすくを心がけてまとめたので参考にしてもらえれば幸いです
トランザクションの分離レベルというのは、ACID性の1つである「分離性」をどの程度まで許容するか、分離性の程度のことを表しています
ACID性とは、トランザクションが持つべき4つの性質のことです
- 原子性 (Atomicity)
- 一貫性 (Consistency)
- 分離性 (Isolation)
- 耐久性 (Durability)
原子性:トランザクションに含まれるタスクが全て実行されるか、あるいは全く実行されないことを保証する性質
一貫性:トランザクション開始と終了時にあらかじめ与えられた整合性を満たすことを保証する性質
分離性:トランザクション中に行われる操作は他のトランザクションに影響を与えないという性質
耐久性:トランザクションの結果は障害が発生した時も失われてはいけないという性質
トランザクションの分離レベルは以下の4種類に分けられます
下に行くほど(分離レベルが高いほど) 整合性・一貫性のレベルは高くなりますが、並列処理性能は低くなります
- READ UNCOMMITTED (リードアンコミット)
- READ COMMITTED (リードコミット)
- REPEATABLE READ (リピータブルリード)
- SERIALIZABLE (シリアライザブル)
※MySQLのデフォルト分離レベルはREPEATABLE READ, PostgreSQLやSQLserverはREAD COMMITTEDです
「整合性・一貫性のレベルは高くなりますが、並列処理性能は低くなります」
ここについて具体的にどういうことか、簡単に検証して解説します!
「整合性・一貫性のレベルは高くなる」とは具体的にどういうことかを READ COMMITED とREPEATABLE READ を例に説明します
それぞれの分離レベルで以下の操作を行います
- トランザクションA(緑文字)からusersテーブルのレコード(id=2645)をSELECT
- トランザクションB(紫文字)から同じレコードをUPDATE
- トランザクションA(緑文字)から再度SELECT
結果は次の通りです
READ COMMITTEDの場合
REPEATABLE READの場合
見てわかる通り、READ COMMITEDの場合、トランザクションBでコミットされた変更を読み取るため、SELECTの結果が1回目(20)と2回目(21)で変わっています
このように他のトランザクションでコミットされた変更を読み取る現象をファジーリード※と呼びます
※ノンリピータブルリードと呼ばれることもあります
一方、REPEATABLE READ の場合、トランザクションBからの変更を読み取らないので、SELECTの結果が1回目(21)と2回目(21)で同じになっています
この結果からも分かるように、分離レベルが高いほど一貫性が保証されるようになっているのです!
続いて「並列処理性は低くなる」とは具体的にどういうことかを SERIALIZABLE と REPEATABLE READ を例に解説します
それぞれの分離レベルで以下の操作を行います
- トランザクションA(緑文字)からusersテーブルのレコード(id = 2645)をSELECT
- トランザクションB(紫文字)から同じレコードをUPDATE
結果は次の通りです
SERIALIZABLEの場合
REPEATABLE READの場合
見て分かる通り、SERIALIZABLEの場合はトランザクションAがコミットされるまでトランザクションBのUPDATEが実行されませんでした
これはなぜかと言うと、SERIALIZABLEの場合はSELECTする行に対して行ロックをかけるため、他のトランザクションからの更新はロックが解放されるまで待たされるのです
一方、REPEATABLE READの場合はSELECT時に行ロックをかけないので他のトランザクションからも即更新することができるのです
この実験結果からも分離レベルが高いほど並列処理性が低くなるということがなんとなくでも分かって頂けたかと思います
なので分離レベルを決める時は、データベースを利用するアプリケーションが一貫性と並列処理性どちらを重視するのかを検討する必要があります
上で「ファジーリード」が出てきましたが、分離レベルによっては、他にも「ダーティーリード」や「ファントムリード」という読み取りの現象が発生します
分離レベルと起こりうる現象は以下のようになっています
分離レベル | ダーティーリード | ファジーリード | ファントムリード |
---|---|---|---|
READ UNCOMMITED | 発生する | 発生する | 発生する |
READ COMMITED | 発生しない | 発生する | 発生する |
REPEATABLE READ | 発生しない | 発生しない | 発生する |
SERIALIZABLE | 発生しない | 発生しない | 発生しない |
いまいちイメージがつかないと思うので、それぞれの現象を確かめながら簡単に解説します
ダーティリードはあるトランザクションが更新している最中に、他のトランザクションがコミットされていない変更を読み取れてしまう現象のことを指します
以下の操作を行って実際に確かめてみます
- トランザクションAでUPDATE (コミットはしない)
- トランザクションBでSELECT
結果は以下のようになりました
READ UNCOMMITEDの場合
REPEATABLE READの場合
READ UNCOMMITEDの場合はトランザクションAでコミットされていない変更をトランザクションBから読み取れてしまっていること(ダーティリード)が確認できました
ファジーリードはあるトランザクションが更新している最中に、他のトランザクションが変更を読み取れてしまう現象のことを指します
以下の操作を行って実際に確かめてみます
- トランザクションAでUPDATE
- トランザクションBでSELECT
- トランザクションAでCOMMIT
- トランザクションBでSELECT
結果は以下のようになりました
READ COMMITTEDの場合
REPEATABLE READの場合
READ COMMITTEDの場合はトランザクションAでコミットされた変更をトランザクションBから読み取れてしまっていること(ファジーリード)を確認できました
MySQLの分離レベルについて私なりにまとめてみました
この記事では基本中の基本だけ解説しているので、もっと詳しく知りたい方はMySQL公式ドキュメントや他の方の記事を読んで理解を深めてください
この記事がプログラミング初心者の方の参考になれば嬉しく思います
最後まで読んで頂きありがとうございました
良ければ他の記事もどうぞ!