はじめに
この記事では、SQL Serverの行バージョニング(Row Versioning)の内部実装を深掘りします。
シリーズ4本目です。SQL Serverは歴史的にロックベースの分離を採用しており、MVCCは後から追加されました。そのため、他のDBとは異なるアーキテクチャになっています。SQL Server 2019 / 2022を中心に解説します。
SQL ServerのMVCC:後付けの設計
InnoDBやOracleは最初からMVCCを前提に設計されています。SQL Serverは違います。
- SQL Server 2005以前:読み取りは共有ロック(S Lock)を取得。書き込みと競合する
- SQL Server 2005〜:RCSI / Snapshot Isolationで行バージョニングを導入
- SQL Server 2019〜:ADR(Accelerated Database Recovery)で新しいバージョンストアを導入
SQL Server用語 InnoDB用語 PostgreSQL用語 Oracle用語
──────────────────────────────────────────────────────────────────────────────
Version Store UNDO Log Heap内のdead tuple UNDO Segment
tempdb Version Store Undo Tablespace ― UNDO Tablespace
PVS (Persistent ― ― ―
Version Store)
RCSI REPEATABLE READ READ COMMITTED デフォルト動作
Version Store:旧バージョンの保管場所
tempdb Version Store(従来方式)
SQL Server 2005〜2017では、行の旧バージョンはtempdbに格納されます。
User Database:
Data Page: [id=1, salary=5000, version_ptr→] ← 最新版
↓
tempdb (Version Store):
[id=1, salary=4000, version_ptr→] ← 1つ前
↓
[id=1, salary=3000, version_ptr→NULL] ← 2つ前
InnoDBのバージョンチェーン(Roll Ptr)と同じ構造ですが、保管場所がtempdbという点が独特です。
tempdb方式の問題
- tempdbへのI/O負荷が増大
- tempdbの容量管理が必要
- tempdbがボトルネックになりやすい
PVS:Persistent Version Store(SQL Server 2019〜)
ADR(Accelerated Database Recovery)を有効にすると、バージョンストアがユーザーデータベース内に移動します:
ALTER DATABASE MyDB SET ACCELERATED_DATABASE_RECOVERY = ON;ADR有効時:
User Database:
Data Page: [id=1, salary=5000] ← 最新版
PVS Page: [id=1, salary=4000] ← 旧版(同じDB内)
InnoDBのUndo Tablespaceに近い設計になりました。
分離レベルと行バージョニング
SQL Serverでは、行バージョニングを使うかどうかは分離レベルの設定次第です。
デフォルト(READ COMMITTED、ロックベース)
-- デフォルトではロックベース
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT * FROM employees WHERE id = 1;
-- → 共有ロック(S Lock)を取得。書き込みトランザクションがあればブロックされるRCSI(Read Committed Snapshot Isolation)
-- データベースレベルで有効化
ALTER DATABASE MyDB SET READ_COMMITTED_SNAPSHOT ON;
-- 以降、READ COMMITTEDがバージョニングベースになる
SELECT * FROM employees WHERE id = 1;
-- → ロックなし。Version Storeから一貫した読み取りSnapshot Isolation
ALTER DATABASE MyDB SET ALLOW_SNAPSHOT_ISOLATION ON;
SET TRANSACTION ISOLATION LEVEL SNAPSHOT;
BEGIN TRANSACTION;
SELECT * FROM employees WHERE id = 1;
-- → トランザクション開始時点のバージョンを読む(REPEATABLE READ相当)各DBとの比較
| 分離レベル | InnoDB | PostgreSQL | Oracle | SQL Server |
|---|---|---|---|---|
| READ COMMITTED | MVCC(デフォルト) | MVCC | MVCC | ロック(デフォルト)/ RCSI |
| REPEATABLE READ | MVCC(デフォルト) | MVCC | ― | ロック / Snapshot |
| SERIALIZABLE | ロック | SSI | ロック | ロック |
SQL Serverだけが「MVCCを使うかロックを使うか選べる」設計です。
ADR(Accelerated Database Recovery)
SQL Server 2019の目玉機能です。
従来のリカバリの問題
長時間トランザクションのロールバックに時間がかかる問題がありました。Transaction Logにはredo/undo両方が記録されているため、クラッシュリカバリ時のundo phaseが長くなります。
ADRの仕組み
従来のリカバリ:
1. Analysis Phase(ログスキャン)
2. Redo Phase(コミット済みを再適用)
3. Undo Phase(未コミットをロールバック)← 長時間トランザクションがあると遅い
ADR:
1. Analysis Phase
2. Redo Phase
3. Undo Phase ← PVSから即座にロールバック(高速)
ADRではPVS内のバージョンを使って論理的にロールバックするため、undo phaseが大幅に短縮されます。
Version Cleanupと旧版の削除
tempdb方式
バックグラウンドタスクが定期的にVersion Storeをスキャンし、どのトランザクションからも参照されなくなったバージョンを削除します。
-- Version Storeの使用状況を確認
SELECT * FROM sys.dm_tran_version_store_space_usage;
-- tempdbの使用状況
SELECT * FROM sys.dm_db_file_space_usage;ADR方式
PVSのクリーンアップもバックグラウンドで自動実行されます。
各DBの旧版削除比較
| InnoDB | PostgreSQL | Oracle | SQL Server | |
|---|---|---|---|---|
| 方式 | Purge | VACUUM | UNDO循環再利用 | Version Cleanup |
| 自動実行 | 常時 | autovacuum | 自動 | 常時 |
| 問題時の症状 | History List肥大化 | テーブル肥大化 | ORA-01555 | tempdb肥大化 |
まとめ
| トピック | InnoDB | PostgreSQL | Oracle | SQL Server |
|---|---|---|---|---|
| MVCC | 最初から組み込み | 最初から組み込み | 最初から組み込み | 後付け(2005〜) |
| バージョン保管 | UNDO Log | Heap内 | UNDO Segment | tempdb / PVS |
| デフォルト動作 | MVCC | MVCC | MVCC | ロック |
| MVCC有効化 | 不要 | 不要 | 不要 | DB設定が必要 |
| UPDATEの動作 | in-place | 新タプル | in-place | in-place + Version Store |
| 旧版の削除 | Purge | VACUUM | 循環再利用 | Version Cleanup |
次回はDb2 MVCCを解説し、シリーズ全体の比較表でまとめます。