概要
- SQLデータベースの根幹となる トランザクション の基本動作と重要性を解説
- MySQL と Postgres におけるトランザクション管理の違いと仕組み
- 一貫性のある読み取り(Consistent Reads)や アイソレーションレベル の比較
- 同時書き込み時の 競合処理 やロック機構の概要
- データベース設計・運用で知っておくべき代表的なポイントを網羅
トランザクションの基本
- トランザクション とは、複数のデータベース操作を 原子的な単位 でまとめて実行する処理単位
- 典型的なトランザクションは、 読み取り・作成・更新・削除 など複数のクエリ実行を含む
- MySQLやPostgresでは、
begin;で開始しcommit;で確定、途中でrollback;による 取り消し も可能 - トランザクション中の変更は コミット前は他セッションから不可視、コミットで一斉反映
- 障害発生時 や意図的な中断時は、データベースが ロールバック や 復旧機構 (例:PostgresのWAL)で一貫性維持
トランザクションの同時実行とデータの可視性
- 複数セッションが同じデータを扱う場合、 コミット前の変更は他セッションから見えない
- ロールバック時は、 全ての変更がなかったこと になるため、他セッションへ影響を与えない
- Consistent Reads (一貫性のある読み取り)で、各トランザクションは 独立したデータのスナップショット を参照
Postgresのマルチバージョン制御(MVCC)
- Postgresは 行の複数バージョン を管理し、各バージョンに
xmin(作成トランザクションID)とxmax(削除トランザクションID)を付与 - 新しいトランザクションが行を更新すると、 新バージョンが生成 され、古いバージョンも一定期間保持
- コミット前の変更は他トランザクションから不可視、コミット後にのみ新バージョンが参照可能
- VACUUM FULL コマンドで、不要な古いバージョンを削除しテーブルを圧縮
MySQLのUndo Log方式
- MySQLは 行データを即時上書き しつつ、 Undo Log で直近の変更履歴を保持
- 各行に
xid(最新更新トランザクションID)やptr(Undo Log参照)などのメタデータを付与 - 他トランザクションからはUndo Logを参照して 必要な過去バージョンを動的復元
- Postgresのような VACUUM操作は不要 だが、Undo Logの管理が重要
アイソレーションレベル
- データベースは 4段階のアイソレーションレベル をサポート
- Serializable :最も厳格。全トランザクションが直列実行されたかのように振る舞う
- Repeatable Read :同一トランザクション内で同じSELECTは常に同じ結果
- Read Committed :コミット済みの変更のみ参照可能。 非再現読取 や ファントムリード が発生
- Read Uncommitted :未コミットの変更も参照可能。 ダーティリード が発生しやすい
- アイソレーションレベルが高いほど 一貫性は高いがパフォーマンス低下 の可能性
ファントムリード・非再現読取・ダーティリード
- ファントムリード :同一SELECTで結果が変化する現象。Repeatable Read以下で発生
- 非再現読取 :同じ行を複数回SELECTし、他のコミット済み変更で値が変わる現象。Read Committed以下で発生
- ダーティリード :未コミットの他トランザクション変更を読めてしまう現象。Read Uncommittedで発生
同時書き込み時の競合制御
-
MySQL は 行レベルロック で競合処理
- 共有ロック(Sロック) :複数トランザクションが同時に取得可能(主に読取時)
- 排他ロック(Xロック) :1つのトランザクションのみ取得可能(更新時)
-
Postgres や他DBも、アイソレーションレベルや内部実装により異なるロック戦略を採用
まとめ
- トランザクション管理は データ整合性とパフォーマンスの両立 に不可欠
- MySQL と Postgres は異なる実装で同様の目的を達成
- 適切な アイソレーションレベル 選択と ロック制御 理解が、堅牢なアプリケーション設計の鍵