Delta Lake の内部構造:ACID、タイムトラベル、スキーマエボリューション

この記事について

Delta Lake はレイクハウスアーキテクチャの核心技術である。オブジェクトストレージ上の Parquet ファイルに ACID トランザクション、スキーマ管理、バージョン管理を追加する。この記事では Delta Lake の内部構造を解説する。

1. Delta Lake とは

1-1. 基本構造

Delta Lake テーブルは、Parquet ファイル + トランザクションログ(_delta_log/)で構成される。

s3://datalake/sales/
  ├── _delta_log/                    ← トランザクションログ
  │   ├── 00000000000000000000.json  ← Version 0
  │   ├── 00000000000000000001.json  ← Version 1
  │   ├── 00000000000000000002.json  ← Version 2
  │   └── 00000000000000000010.checkpoint.parquet  ← チェックポイント
  ├── part-00000-xxx.parquet         ← データファイル
  ├── part-00001-xxx.parquet
  └── part-00002-xxx.parquet

1-2. トランザクションログ

各 JSON ファイルが1つのトランザクション(バージョン)を表す。

// 00000000000000000001.json の例
{
  "add": {
    "path": "part-00003-xxx.parquet",
    "size": 1048576,
    "partitionValues": {"date": "2024-04-01"},
    "stats": "{\"numRecords\":10000,\"minValues\":{\"amount\":1},\"maxValues\":{\"amount\":99999}}"
  }
}

ログに記録されるアクション:

アクション 説明
add ファイルの追加
remove ファイルの論理削除
metaData スキーマ変更
txn アプリケーショントランザクション ID
protocol プロトコルバージョン
commitInfo コミットのメタデータ(タイムスタンプ、操作種別)

2. ACID トランザクション

2-1. 楽観的同時実行制御

Delta Lake は楽観的同時実行制御(Optimistic Concurrency Control)を採用。

Writer A: Version 2 を読み取り → 変換処理 → Version 3 として書き込み ✅
Writer B: Version 2 を読み取り → 変換処理 → Version 3 として書き込み ❌ 競合
  → Writer B は Version 3 を読み直して再試行

競合検出のルール: – 同じファイルを変更する場合 → 競合 – 異なるパーティションへの書き込み → 競合しない

2-2. 読み取りの一貫性

読み取りは特定のバージョンのスナップショットを参照する。書き込み中のデータは見えない(Snapshot Isolation)。

Reader: Version 5 のスナップショットを読み取り
Writer: Version 6 を書き込み中
→ Reader には Version 6 の変更は見えない

3. タイムトラベル

過去の任意のバージョンのデータを参照できる。

-- バージョン指定
SELECT * FROM sales VERSION AS OF 5;

-- タイムスタンプ指定
SELECT * FROM sales TIMESTAMP AS OF '2024-04-01 00:00:00';

用途: – データの誤更新からの復旧 – 監査(過去の状態の確認) – ML モデルの再現性(学習時のデータを再取得)

4. スキーマエンフォースメントとエボリューション

4-1. スキーマエンフォースメント

テーブル定義と異なるスキーマのデータを書き込もうとするとエラーになる。

テーブル定義: [id: INT, name: STRING, amount: DECIMAL]

書き込みデータ: [id: INT, name: STRING, amount: DECIMAL, tax: DECIMAL]
→ エラー: tax カラムがテーブル定義にない

4-2. スキーマエボリューション

明示的にスキーマ変更を許可する。

-- カラム追加を許可して書き込み
ALTER TABLE sales ADD COLUMN tax DECIMAL(10,2);

-- または書き込み時に mergeSchema オプション

対応する変更: – カラムの追加 – カラムの型の拡張(INT → LONG 等) – ネストされた構造の変更

5. データ最適化

5-1. OPTIMIZE(Compaction)

小さなファイルを結合して最適なサイズにする。

OPTIMIZE sales;
-- 小さなファイルを結合 → 読み取り性能向上

5-2. Z-ORDER

指定カラムの値が近いデータを同じファイルにまとめる。複数カラムでのフィルタリングを高速化。

OPTIMIZE sales ZORDER BY (product_id, region);
-- product_id と region でフィルタするクエリが高速化

5-3. VACUUM

タイムトラベルで不要になった古いファイルを物理削除する。

VACUUM sales RETAIN 168 HOURS;  -- 7日より古いファイルを削除

デフォルトの保持期間は7日。これより短くするとタイムトラベルができなくなる。

5-4. Liquid Clustering(新機能)

従来のパーティション + Z-ORDER を置き換える新しいデータ配置手法。

CREATE TABLE sales CLUSTER BY (date, region);
-- パーティションと Z-ORDER を統合的に管理

メリット: – パーティションキーの事前設計が不要 – クラスタリングキーを後から変更可能 – OPTIMIZE 時に自動的に最適化

6. Delta Lake vs Iceberg vs Hudi

観点 Delta Lake Apache Iceberg Apache Hudi
開発元 Databricks Netflix → Apache Uber → Apache
ACID
タイムトラベル
スキーマエボリューション
パーティションエボリューション △(Liquid Clustering) ✅(Hidden Partitioning)
エンジン依存 Spark 中心(他も対応拡大中) エンジン非依存 Spark 中心
Upsert / CDC ✅ MERGE ✅ MERGE ✅(CDC に特化)
コミュニティ Databricks 主導 幅広い(AWS, Apple 等) Uber 主導

Databricks は Delta Lake を推進しつつ、UniForm 機能で Iceberg / Hudi との互換性も提供している。

7. まとめ

機能 説明
トランザクションログ JSON ファイルで全変更を記録。ACID の基盤
ACID 楽観的同時実行制御 + Snapshot Isolation
タイムトラベル 過去の任意のバージョンを参照可能
スキーマ管理 エンフォースメント(拒否)+ エボリューション(許可)
OPTIMIZE ファイル結合 + Z-ORDER でクエリ高速化
VACUUM 不要ファイルの物理削除

Delta Lake は「S3 上の Parquet ファイルに RDBMS の管理機能を追加する」技術。これがレイクハウスの核心。

参考文献

  • Michael Armbrust et al. “Delta Lake: High-Performance ACID Table Storage over Cloud Object Stores.” VLDB, 2020.
  • Databricks. “Delta Lake Documentation.” https://docs.delta.io/latest/
  • Databricks. “Delta Lake Internals.” https://www.databricks.com/blog/2019/08/21/diving-into-delta-lake-unpacking-the-transaction-log.html

コメントする