InnoDBはファントムリードをどのように解決しますか?
InnoDBはMVCC(マルチバージョン・コンカレンシー・コントロール)を利用してファントムリード問題に対処しています。ファントムリードとは、同一トランザクションにおいて、2回のクエリの実行結果が異なることを指します。
InnoDBは行データごとにシステムバージョン番号を保存することでMVCCを実現します。トランザクションが開始すると、そのトランザクションには一意のトランザクションIDが割り当てられます。データを検索する際には、InnoDBはその検索トランザクションのトランザクションIDと、行のバージョン番号によって可視性(見えているかどうか)を判断します。
トランザクションの開始時に、InnoDBはそのトランザクションのread viewとして現在のトランザクションIDを格納し、トランザクションのread view listに保持します。後続のクエリにおいて、InnoDBは各行データの可視性を判断するために、そのトランザクションのread viewを利用します。
InnoDBは、トランザクションがSELECT文を実行した時に、次のルールに従って行の可視性を決定します:
- 行のバージョン番号が現在のトランザクションIDより低い場合、行は現在のトランザクションに対して可視である。
- 行のバージョン番号が現在のトランザクションIDより大きい場合、行は現在のトランザクションからは見えない
- 行のバージョン番号が現在のトランザクションIDに等しい場合、行の削除マーク(delete_mark)によってその行が現在のトランザクションに対して可視かどうかを判断する必要があります。
InnoDBはSELECT文の実行時に条件を満たす行のバージョン番号と現在の実行中のトランザクションIDを比較し、バージョン番号がトランザクションIDより小さければ結果セットに追加し、バージョン番号がトランザクションIDより大きければ無視します。
InnoDBはMVCCを利用して挿入の幻読を抑止しています。更新と削除では、トランザクションIDを元に新しいバージョン番号を生成し、対象となる行に適用しています。この方法であれば同一トランザクション内での2回の検索結果に不整合が生じません。
デフォルトでInnoDBでは、ファントムリードを防ぐREPEATABLE READという分離レベルが設定されています。さらに並行処理能力を向上させたい場合は、READ COMMITTEDやREAD UNCOMMITTEDなどの分離レベルを低く設定することもできますが、ファントムリードが発生する可能性が高くなります。