はじめに
この記事では、Oracle DatabaseのUNDOの内部実装を深掘りします。
InnoDB、PostgreSQLに続く3本目です。Oracleは最も早くMVCCを実装したDBの1つで、UNDO管理の成熟度が高いです。Oracle 19c / 23aiを中心に解説します。
OracleのMVCCアーキテクチャ
OracleはInnoDBと同じく「最新版をテーブルに、旧版をUNDO領域に」保持する方式です。
Oracle用語 InnoDB用語 PostgreSQL用語
──────────────────────────────────────────────────────────
UNDO Segment Rollback Segment ―(Heap内に保持)
UNDO Tablespace Undo Tablespace ―
CR Clone バージョンチェーン xmin/xmax
SCN Transaction ID Transaction ID
ORA-01555 ― ―
UNDO Segmentの構造
UNDO Tablespace
OracleのUNDOデータは専用のUNDO Tablespaceに格納されます。
SHOW PARAMETER undo;
NAME VALUE
-------------------- ---------------
undo_management AUTO
undo_retention 900 -- 秒(デフォルト15分)
undo_tablespace UNDOTBS1UNDO Segment
UNDO Tablespace内に複数のUNDO Segmentがあります。各トランザクションは1つのUNDO Segmentに割り当てられます。
SELECT segment_name, status, tablespace_name
FROM dba_rollback_segs WHERE tablespace_name = 'UNDOTBS1';
SEGMENT_NAME STATUS TABLESPACE_NAME
-------------- -------- ---------------
_SYSSMU1$ ONLINE UNDOTBS1
_SYSSMU2$ ONLINE UNDOTBS1
...UNDO Segment内はエクステント(連続ブロック群)で構成され、循環的に再利用されます。InnoDBのRollback Segmentと同じ概念です。
CR Clone(Consistent Read)
Oracleの読み取り一貫性の核心がCR Clone(Consistent Read Clone)です。
仕組み
読み取りトランザクションがデータブロックにアクセスしたとき、そのブロックに自分のSCN以降の変更が含まれていたら:
1. データブロックのコピーをメモリ上に作成(CR Clone)
2. UNDO Segmentから旧値を取得
3. CR Cloneに旧値を適用(ロールバック)
4. 必要なだけ繰り返して、自分のSCN時点の状態を復元
5. CR Cloneから読み取る
Buffer Cache:
Current Block: [id=1, salary=5000, SCN=200] ← 最新版
読み取りTx(SCN=150で開始)がアクセス:
→ SCN 200 > 150 なので、CR Cloneを作成
→ UNDO Segmentから SCN=200 の変更前値を取得
→ CR Clone: [id=1, salary=3000, SCN=100] ← SCN=150時点の状態
InnoDBとの比較
| InnoDB | Oracle | |
|---|---|---|
| 旧版の取得 | UNDO LogのRoll Ptrを辿る | CR Cloneを作成しUNDOを適用 |
| 旧版の場所 | UNDO Log内のレコード | Buffer Cache上のCR Clone |
| コスト | チェーンが長いと遅い | ブロック全体のコピー+ロールバック |
ORA-01555:Snapshot Too Old
PostgreSQLにはテーブル肥大化の問題がありました。OracleにはUNDO領域の上書きによるORA-01555があります。
発生メカニズム
1. 長時間の読み取りクエリが開始(SCN=100)
2. 他のトランザクションがデータを更新し続ける
3. UNDO Segmentが循環利用され、SCN=100時点のUNDOデータが上書きされる
4. 読み取りクエリがCR Cloneを作ろうとするが、必要なUNDOがもうない
5. ORA-01555: snapshot too old
対策
-- UNDO保持時間を延長(デフォルト900秒)
ALTER SYSTEM SET undo_retention = 3600; -- 1時間
-- UNDO Tablespaceを十分に大きくする
ALTER TABLESPACE UNDOTBS1 ADD DATAFILE '/u01/oradata/undotbs02.dbf' SIZE 10G;
-- Guaranteed Undo Retention(UNDOの上書きを禁止)
ALTER TABLESPACE UNDOTBS1 RETENTION GUARANTEE;| InnoDB | PostgreSQL | Oracle | |
|---|---|---|---|
| UNDO不足の症状 | History List肥大化 | テーブル肥大化 | ORA-01555 |
| 原因 | 長時間Tx/ReadView | VACUUMの遅延 | UNDO上書き |
| 対策 | Purge高速化 | autovacuumチューニング | undo_retention延長 |
Automatic Undo Management
Oracle 9i以前は手動でRollback Segmentを管理する必要がありました。9i以降はAUM(Automatic Undo Management)がデフォルトです。
AUMでは: – UNDO Segmentの数とサイズを自動調整 – トランザクションへのUNDO Segment割り当てを自動化 – undo_retentionに基づいてUNDOの保持期間を管理
InnoDBも同様に自動管理です。PostgreSQLはそもそもUNDO領域が不要(Heap内にバージョンを保持)なので、この問題自体がありません。
まとめ
| トピック | InnoDB | PostgreSQL | Oracle |
|---|---|---|---|
| バージョン保管 | UNDO Log | Heap内 | UNDO Segment |
| 読み取り一貫性 | ReadView + Roll Ptr | Snapshot + xmin/xmax | CR Clone |
| UPDATEの動作 | in-place更新 | 新タプル挿入 | in-place更新 |
| UNDO不足時 | History List肥大化 | テーブル肥大化 | ORA-01555 |
| 旧版の削除 | Purge | VACUUM | UNDO Segmentの循環再利用 |
| 管理 | 自動 | autovacuum | AUM(自動) |
次回はSQL Server Versioningを解説します。