トランザクション分離レベルとMVCC(多版型同時実行制御)の内部動作のサムネイル
ガイドDB

トランザクション分離レベルとMVCC(多版型同時実行制御)の内部動作

公開: 2026-10-05更新: 2026-10-06
分離レベルの標準上の許容現象とDBMSの実装を分けて解説。MVCCのスナップショット、書込みスキュー、座席予約の条件付きUPDATEを確認します。

分離レベルは、同時実行中のデータがどう見えるかを定めます。MVCCは過去の行バージョンなどから一貫した読み取りを提供する仕組みですが、分離レベルの名称と実装は一対一ではありません。標準上許される現象と、利用するDBMSが実際に防ぐ現象を分けて確認します。

標準上の許容現象と、製品の違い

分離レベル

ダーティリード

非反復可能読取り

ファントム

Read Uncommitted

許容

許容

許容

Read Committed

禁止

許容

許容

Repeatable Read

禁止

禁止

許容

Serializable

禁止

禁止

禁止

ダーティリードは他処理の未確定データを読むこと、非反復可能読取りは同じ行の再読取りで値が変わること、ファントムは同じ条件の再検索で対象の集合が変わることです。ファントムはINSERT・DELETEだけでなく、条件列の更新でも起こり得ます。

表は標準上の許容を示しています。PostgreSQLのRead UncommittedはRead Committedとして動作し、Repeatable Readはファントムも防ぎます。ただしRepeatable Readでも直列化異常が残り得ます。「Repeatable ReadならすべてのDBMSでファントムを防ぐ」とは言えません。

スナップショットと、ロックの残る場面

通常のMVCC読み取りは、自分のスナップショットに可視な行バージョンを参照します。PostgreSQLのRead Committedでは原則として各SQL文の開始時、Repeatable Readでは最初の非トランザクション制御文の時点に基づくスナップショットを使います。単にトランザクションIDの大小だけで可視性を決めるわけではなく、実行中・確定済みの状態も必要です。

通常のSELECTとUPDATEが行単位で待たせ合いにくいことがMVCCの利点ですが、「読み取りは絶対にロックしない」とは限りません。SELECT FOR UPDATEなどの明示的ロックやDDLとの競合では待ちが発生します。旧バージョンを回収できない長時間トランザクションは、保存領域やメンテナンスにも影響します。

書込みスキュー:異なる行でも全体制約が壊れる

当直医A・Bが勤務中で、少なくとも1人の勤務が必要とします。T1とT2が同じスナップショットで2人を確認し、T1がA、T2がBを別々に勤務終了へ更新すると、同じ行の更新競合がなくても当直医が0人になります。これはスナップショット分離で起こり得る書込みスキューです。

対策は、業務制約に関係する読み取り・更新を直列化することです。共有する当直枠の管理行をロックしてから人数を再評価する、またはSerializableで直列化失敗を検知してトランザクション全体を再試行する方法があります。既存の対象行をFOR UPDATEで取るだけでは、新規行の追加や分離レベル固有の見え方まで一律に解決できないので、守る対象を明確にします。

同じ行の競合と書込みスキュー異なる行でも、判断根拠となる共通の業務制約を同時に壊すことがあります。同じ行の更新書込みスキュー更新対象同じ座席など別の医師など必要な確認更新条件・競合集合全体の制約対策の候補条件付き更新共有行のロック・直列化
同じ行の競合と書込みスキュー

異なる行でも、判断根拠となる共通の業務制約を同時に壊すことがあります。

座席予約は、確認と更新の間を守る

Read Committedで、空席をSELECTしてから条件なしにUPDATEすると、両利用者が空席と判断し、後の更新が先の予約者を上書きし得ます。表に2行が残るとは限りませんが、双方に予約成功を返すという業務上の不整合が生じます。

sql
UPDATE 座席
SET 予約状態 = '仮確保', 予約会員ID = 20
WHERE 公演ID = 101 AND 座席番号 = 'A-1'
  AND 予約状態 = '空席';

状態条件をUPDATE自身へ入れ、更新行数が1件の場合だけ成功を返します。0件なら確保失敗として扱います。PostgreSQLのRead Committedでは、競合更新を待った後に更新済みの行に対して条件を再評価します。予約の取消、仮確保期限、決済結果まで含めた設計では、それぞれの状態遷移条件も必要です。

演習1:当直医の異常

条件:T1とT2は2人の当直を見た後、別々の医師を勤務終了にした。

問い:なぜ行の排他ロックだけでは全体制約が守られなかったか。

解答例:更新した行が異なり、当直医が1人以上という共通の判断条件が保護されていなかったため。

根拠:同じ行の更新を排他にしても、別行同士の依存による直列化異常は残る。

演習2:予約UPDATEの条件

条件:更新前の空席SELECTと、座席番号だけによるUPDATEを行っている。

問い:UPDATEへ追加する状態条件を答えよう。(35字以内)

解答例:予約状態が空席の場合だけ更新する。(17字)

根拠:更新行数が1件であることも成功判定に必要。

復習で確かめること

例の数値や業務条件を変えて同じ結論になるか確認してください。用語の定義だけでなく、問題文のどの条件から、どの制約・SQL・対策を選んだのかを自分の言葉で説明できれば、次の過去問に進みます。

出典と仕様を確認する

IPA:DBシラバス Ver.4.1

PostgreSQL 18:分離レベル

PostgreSQL 18:MVCC

PostgreSQL 18:明示的なロック

関連するテーマ

トランザクションACID特性とロック機構・デッドロック回避の設計

高度なSQL構文とクエリ最適化(相関副問合せ・Window関数・EXISTS)

次におすすめの学習

この記事を共有する

編集・検証について

編集・検証:IT資格ラボ編集部

IPAが公開する試験要綱・シラバス・過去問題と、各技術の公式資料を優先して内容を確認しています。制度変更や誤りを確認した場合は、記事を見直して更新します。

編集方針・情報源・訂正方針を見る