Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

ファントムリード(ファントムリード)とは | 意味や読み方など丁寧でわかりやすい用語解説

ファントムリード(ファントムリード)の意味や読み方など、初心者にもわかりやすいように丁寧に解説しています。

作成日: 更新日:

読み方

日本語表記

ファントムリード (ファントムリード)

英語表記

Phantom Read (ファントムリード)

用語解説

ファントムリードとは、データベースにおいて、あるトランザクションが同じ検索条件で複数回データを読み取った際、その間に別のトランザクションによって条件に合致する新しいレコードが挿入されたり、既存のレコードが削除・更新されたりした結果、最初の読み取りと異なるレコード集合が検出される現象を指す。これは、あたかもデータが幻のように出現したり消えたりすることから名付けられた、データベースの並行性制御における問題の一つである。

データベースは、複数のユーザーやアプリケーションが同時にアクセスし、データを読み書きする環境で運用されることが多い。このような並行処理の環境でデータの一貫性や整合性を保つため、「トランザクション」という仕組みが用いられる。トランザクションは、一連のデータベース操作を一つの論理的な単位としてまとめ、その単位内のすべての操作が成功するか、あるいはすべて失敗するか(コミットまたはロールバック)を保証する。しかし、複数のトランザクションが同時に実行されると、互いの操作が干渉し、予期せぬ結果を引き起こす可能性があるため、データの正確性を保つために「分離レベル」が導入されている。分離レベルは、トランザクションが他のトランザクションの変更からどれだけ隔離されるかを示す度合いであり、一般的にリードアンコミッティド、リードコミッティド、リピータブルリード、シリアライザブルの4段階がある。

ファントムリードは、リードコミッティドやリピータブルリードといった分離レベルで発生する可能性がある。具体的な発生シナリオを考える。例えば、トランザクションAが「注文数が10個以上の顧客」を検索し、その時点で見つかった顧客の数をNとする。この後、トランザクションBが実行され、トランザクションAの検索条件に合致する新しい顧客レコードをデータベースに挿入する、あるいは既存の顧客レコードを更新して注文数を10個以上にする。その後、トランザクションAが再び、まったく同じ条件でデータベースを検索する。すると、トランザクションAは初回に検索した時とは異なる結果、例えばN個よりも多いM個の顧客レコードを検出する。これは、トランザクションAの処理中に、条件に合致する新しいレコードが「出現した」ことを意味する。逆に、トランザクションBが条件に合致していたレコードを削除した場合、二度目の検索でレコードが「消失した」と検出されることもある。リピータブルリード分離レベルでは、既に読み込んだ特定のレコードが他のトランザクションによって変更されることは防ぐが、新しいレコードの挿入や既存レコードの削除によってデータ集合自体が変わることは防げないため、ファントムリードが発生しうるのである。

ファントムリードが発生すると、アプリケーションのロジックが期待しない結果を受け取り、データの一貫性が損なわれる可能性がある。例えば、ある集計処理を行うトランザクションが、処理の途中で新しいデータが挿入されたために集計結果が不正になる、あるいはデータの存在を前提とした処理が、そのデータが消えたために失敗するといった問題が起こりうる。特に、一連の処理の中でデータ集合の「安定性」が求められるような場面、例えば、在庫数を確定する処理や、特定の条件を満たす全データに対して一括で処理を行う場合などに、ファントムリードはバグやデータ破損の原因となり得る。開発者は、このような現象を考慮せずにプログラムを作成すると、予期せぬ動作やデータの不整合に直面することになる。

ファントムリードを防ぐ最も確実な方法は、データベースの分離レベルを「シリアライザブル」に設定することである。この分離レベルは、複数のトランザクションが並行して実行されても、あたかもそれらが一つずつ順次実行されたかのように振る舞うことを保証し、ファントムリードを含むすべての並行性問題を防ぐ。しかし、シリアライザブル分離レベルは、他の分離レベルに比べて最も厳しい隔離を提供する分、トランザクション間のロック競合が頻繁に発生し、並行性が大きく低下する可能性がある。その結果、システムのパフォーマンスが著しく低下したり、デッドロックの発生頻度が高まったりするリスクがあるため、利用には慎重な検討が必要となる。システムの要件とパフォーマンス要件を比較検討し、適切な分離レベルを選択することが重要である。また、分離レベルの変更が難しい場合や、特定の箇所でのみファントムリードを防ぎたい場合は、アプリケーション側で明示的なロック(共有ロックや排他ロック)を適切に利用したり、トランザクション内で同じ検索を複数回行わないようにロジックを設計したりすることも考慮される。

関連コンテンツ