PostgreSQLのMVCC(Multi-Version Concurrency Control)では、各トランザクションが見るべきレコードのバージョンを効率的に見つける仕組みとして、以下のような方法が使われています。
-
Heap Tuple:
- PostgreSQLでは、テーブルに格納される各行(レコード)はHeap Tupleとして管理されます。
- Heap Tupleには、各トランザクションが使用するためのバージョン情報が含まれています。
-
バージョン管理:
- 各Heap Tupleには以下の情報が含まれています:
xmin: このレコードを作成したトランザクションID。xmax: このレコードを削除または更新したトランザクションID(削除や更新前のレコードに記録される)。- 可視性マップ(Visibility Map)やFreeze情報なども補助的に使われます。
- 各Heap Tupleには以下の情報が含まれています:
-
トランザクションのスナップショット:
- トランザクションは開始時にスナップショットを取得します。
- スナップショットは「どのトランザクションがコミット済みで、どのトランザクションが未コミットか」を記録しています。
トランザクションが対象レコードを検索する際、以下の手順で「見るべきバージョン」を判定します。
-
xminとxmaxのチェック:- スナップショットを基に、対象レコードの
xminとxmaxを調べます。 - 条件:
- 現在のトランザクションが
xminのトランザクションを認識しており、それがコミット済みである。 xmaxが設定されていない、またはxmaxのトランザクションが未コミットである(つまり削除されていない)。
- 現在のトランザクションが
- スナップショットを基に、対象レコードの
-
トランザクションの状態を確認:
xminやxmaxが指すトランザクションが現在どういう状態か(コミット済み、未コミット、またはアボート済みか)を確認します。- 必要に応じて、トランザクションログ(Transaction Log, 通称
pg_clogやpg_xact)を参照します。
-
可視性判定:
- 判定条件に基づき、そのレコードバージョンが現在のトランザクションに「見える」かどうかを確認します。
PostgreSQLでは、MVCCによる可視性チェックを効率化するために、いくつかの最適化が行われています。
-
Visibility Map:
- 各ページ(データブロック)ごとに「全てのレコードが可視である」かどうかを記録するビットマップ。
- 全可視ページは細かいチェックをスキップできる。
-
行ロックと遅延削除(HOT Updates):
- 同じページ内で更新されたレコードは特定のリンク構造(HOTチェイン)を持つため、関連レコードを効率的に追跡できます。
-
Index-Only Scan:
- インデックスだけで必要なデータを取得できる場合、Heap Tupleの可視性チェックを省略します。
-
Freeze(フリーズ処理):
- 古いトランザクションIDを「フリーズ」して、これ以上のチェックを不要にします。
トランザクションが見るべきバージョンを見つけるプロセスは次のような流れです:
- Heap Tupleの
xminとxmaxを調査。 - スナップショットに基づき可視性を判定。
- 必要に応じて、トランザクションログや関連する最適化構造を参照。
これにより、トランザクション間での整合性を保ちながら、効率的なデータアクセスが可能になります。