Lapis Lazuli

technical blog for web developer

【DB】トランザクション分離レベルには気をつける

DBのパフォーマンスが問題になり、かつトランザクションを使用している時には、トランザクション分離レベルがパフォーマンスを落としている可能性があります。
普段はここを意識する事は少ないと思いますが、最近パフォーマンス調査で触れる機会があったのでまとめてみました。

トランザクション分離レベルとは

トランザクションの厳密性をレベル分けしたものです。
トランザクションは読み込みに対して、不都合が出ないように厳密であればあるほどパフォーマンスが悪化します。
主に下記のレベルに分けられています。

1 READ UNCOMMITTED
2 READ COMMITTED
3 REPEATABLE READ
4 SERIALIZABLE

4が一番厳密で、1が一番ゆるい規約で定義されています。つまり1が一番パフォーマンスが出せます。
1にすると何が問題かというと、下記の読み取り不具合が出てきます。

A ダーティーリード
B ノンリピータブルリード
C  ファントムリード

Aは他の未コミットのトランザクションのデータが読み取られてしまう現象です。
1でしか発生しません。結構ヤバいやつなので普通はこれにはしないと思います・・・トランザクション使い物にならなくなるので。
Bは他のトランザクションが更新したデータを読み取るので、前後で結果が変わってしまう現象。トランザクション同士が密結合なっちゃってますね。
CはノンリピータブルリードのINSERT版です。他トランザクションが挿入したデータが読み取られてしまう現象。

レベルと読み取り不都合の関係は下記のようになります。

READ UNCOMMITTED

ABC全てを許容する。数百トランザクション走ると結構パフォーマンスに差が出るくらい早い。
これにしているDBは(特殊な事情を除き)無いんじゃないでしょうか。

READ COMMITTED

BCを許容する。3で遅かったらこれに変更する可能性があるポジションですね。ただファントムリードには気をつけないといけない。
PostgreSQLだとデフォルトがこれです。

REPEATABLE READ

MySQLだとデフォルトになっている。Cのみを許容するレベル。パフォーマンスとのバランスが良く、ファントムリードが問題になるシステム以外ならこれでいいと思います。
MySQLに限りファントムリードも起きないので、これより上げることはまずないです。

SERIALIZABLE

全てを許容しない、最も厳密なレベル。
ミスが許されえない所(金融とか)で使われているのでしょうか。これも限定された用途でしか設定しないと思います。


一通りトランザクション分離レベルについて学びましたが、基本的に触らなくてもエンジンがいい感じにしてくれます。
デフォルトでも問題ない設定になってますしね。
ただ、パフォーマンスが落ちたりとかしたときに、ここを疑ってみるのは手段の1つかなとは思います。
だからと言って影響出そうだし即変更とはいきませんが・・・頭の片隅にあると、障害起きた時の原因調査の役に立つ可能性ありますしね。