SQL Server Versioning の内部構造を徹底解説:tempdb Version Store、RCSI、ADR まで

はじめに

この記事では、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を解説し、シリーズ全体の比較表でまとめます。

参考文献

コメントする