【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つかなとは思います。
だからと言って影響出そうだし即変更とはいきませんが・・・頭の片隅にあると、障害起きた時の原因調査の役に立つ可能性ありますしね。