R2 Data Catalog や任意の Apache Iceberg カタログからデータを削除するときは、カタログ経由のトランザクションで操作する必要があります。メタデータやデータファイルを直接手で削除すると、データカタログが壊れることがあります。
R2 Data Catalog は、スナップショットの有効期限切れや compaction などのテーブルメンテナンスを自動で管理できます。継続的なこれらの操作は、レイテンシとストレージコストを抑えます。
- スナップショットの有効期限切れ: 古いスナップショットと、参照されなくなったデータファイルを自動で削除します。メタデータのオーバーヘッドとストレージコストの両方を減らせます。
- compaction: 小さいデータファイルを大きいファイルへマージします。読み取り性能を最適化し、クエリ時に読むファイル数を減らします。
自動メンテナンスを有効にしない場合は、これらの操作を手動で行う必要があります。
詳細は テーブルメンテナンス のドキュメントを参照してください。
# Enable automatic snapshot expiration for entire catalog
npx wrangler r2 bucket catalog snapshot-expiration enable my-bucket \
--older-than-days 30 \
--retain-last 5
# Enable automatic compaction for entire catalog
npx wrangler r2 bucket catalog compaction enable my-bucket \
--target-size 256追加の例は カタログを管理する のドキュメントを参照してください。
次の場合は、データを手動で削除する必要があります。
- GDPR や CCPA などのデータ保持ポリシーへの対応。
- 条件付きロジックによる選択的な削除。
- R2 Data Catalog が管理しない、古いファイルや参照されていないファイルの削除。
次は PySpark を使った基本的な例です。同様の操作は、ほかの Iceberg 互換エンジンでも実行できます。PySpark の設定は、サンプル または公式の PySpark ドキュメント ↗ を参照してください。
# Creates new snapshots and marks old files for cleanup
spark.sql("""
DELETE FROM r2dc.namespace.table_name
WHERE column_name = 'value'
""")
# The following is effectively a TRUNCATE operation
spark.sql("DELETE FROM r2dc.namespace.table_name")
# For large deletes, use partitioned tables and delete entire partitions for faster performance:
spark.sql("""
DELETE FROM r2dc.namespace.table_name
WHERE date_partition < '2024-01-01'
""")# Removes table from catalog but keeps data files in R2 storage
spark.sql("DROP TABLE r2dc.namespace.table_name")
# ⚠️ DANGER: Permanently deletes all data files from R2
# This operation cannot be undone
spark.sql("DROP TABLE r2dc.namespace.table_name PURGE")
# Use CASCADE to drop all tables within the namespace
spark.sql("DROP NAMESPACE r2dc.namespace_name CASCADE")
# You will need to PURGE the tables before running CASCADE to permanently delete data files
# This can be done with a loop over all tables in the namespace
tables = spark.sql("SHOW TABLES IN r2dc.namespace_name").collect()
for row in tables:
table_name = row['tableName']
spark.sql(f"DROP TABLE r2dc.namespace_name.{table_name} PURGE")
spark.sql("DROP NAMESPACE r2dc.namespace_name CASCADE")# Remove old metadata and data files marked for deletion
# The following retains the last 5 snapshots and deletes files older than Nov 28, 2024
spark.sql("""
CALL r2dc.system.expire_snapshots(
table => 'r2dc.namespace_name.table_name',
older_than => TIMESTAMP '2024-11-28 00:00:00',
retain_last => 5
)
""")
# Removes unreferenced data files from R2 storage (orphan files)
spark.sql("""
CALL r2dc.system.remove_orphan_files(
table => 'namespace.table_name'
)
""")
# Rewrite data files with a target file size (e.g., 512 MB)
spark.sql("""
CALL r2dc.system.rewrite_data_files(
table => 'r2dc.namespace_name.table_name',
options => map('target-file-size-bytes', '536870912')
)
""")Apache Iceberg は、階層化されたメタデータ構造でテーブルデータを効率よく管理します。主な構成要素とファイル構造は次のとおりです。
- metadata.json: 現在のスナップショットを指す最上位の JSON ファイル
- snapshot-*: ある時点の不変なテーブル状態
- manifest-list-*.avro: あるスナップショットのすべてのマニフェストファイルを列挙する Avro ファイル
- manifest-file-*.avro: データファイルとその統計を追跡する Avro ファイル
- data-*.parquet: 実際のテーブルデータを含む Parquet ファイル
- 注意: 変更されていないマニフェストファイルは、スナップショット間で再利用されます
- metadata.json メタデータファイル - 現在のスナップショットを指します
- テーブルスキーマ
- パーティション仕様
- ソート順
- スナップショット
- snapshot-3051729675574597004.avro スナップショット 1(過去)
- manifest-list-abc123.avro マニフェストリスト
- manifest-file-001.avro マニフェストファイル
- data-00001.parquet (10 MB, 50K rows)
- data-00002.parquet (12 MB, 60K rows)
- data-00003.parquet (11 MB, 55K rows)
- manifest-file-002.avro
- data-00004.parquet (9 MB, 45K rows)
- data-00005.parquet (10 MB, 50K rows)
- manifest-file-001.avro マニフェストファイル
- manifest-list-abc123.avro マニフェストリスト
- snapshot-3051729675574597005.avro スナップショット 2(現在)
- manifest-list-def456.avro マニフェストリスト
- manifest-file-001.avro (スナップショット 1 から再利用)
- data-00001.parquet
- data-00002.parquet
- data-00003.parquet
- manifest-file-003.avro (新規)
- data-00006.parquet (11 MB, 53K rows)
- data-00007.parquet (10 MB, 51K rows)
- data-00008.parquet (12 MB, 58K rows)
- manifest-file-001.avro (スナップショット 1 から再利用)
- manifest-list-def456.avro マニフェストリスト
- snapshot-3051729675574597004.avro スナップショット 1(過去)
Apache Iceberg は Copy-on-Write(COW) と Merge-on-Read(MOR) の 2 つの削除モードに対応しています。どちらも新しいスナップショットを作り、古いファイルをクリーンアップ対象としてマークします。削除の扱い方は次のように異なります。
| 観点 | Copy-on-Write(COW) | Merge-on-Read(MOR) |
|---|---|---|
| 削除の仕組み | 削除行を除いたデータファイルを書き直します | スキップする行を示す削除ファイルを作成します |
| クエリ性能 | 速い(マージ不要) | 遅い(読み取り時のマージが必要) |
| 書き込み性能 | 遅い(データファイルを書き直す) | 速い(削除マーカーだけを書く) |
| ストレージへの影響 | すぐに新しいデータファイルを作成します | 時間とともに削除ファイルが蓄積します |
| 必要なメンテナンス | スナップショットの有効期限切れ | スナップショットの有効期限切れ + compaction(rewrite_data_files) |
| 向いている用途 | 読み取りが多いワークロード | 小さい変更が頻繁な、書き込みが多いワークロード |
これらの操作は、COW テーブルと MOR テーブルの両方で同じように動作します。
| 操作 | 内容 | データを削除するか | 元に戻せるか |
|---|---|---|---|
DELETE FROM |
条件に一致する行を削除します | いいえ(クリーンアップ対象としてマーク) | タイムトラベル経由1 |
DROP TABLE |
カタログからテーブルを削除します | いいえ | はい(データファイルが残っている場合) |
DROP TABLE ... PURGE |
テーブルを削除し、データも削除します | はい | いいえ |
expire_snapshots |
古いスナップショット / ファイルを片付けます | はい | いいえ |
remove_orphan_files |
参照されていないファイルを削除します | はい | いいえ |
Merge-on-Read テーブルでは、性能のために削除を手動で適用する必要がある場合があります。
| 操作 | 内容 | 使うタイミング |
|---|---|---|
rewrite_data_files(compaction) |
削除を適用し、ファイルをまとめます | 削除ファイルが増えてクエリ性能が落ちたとき |
- テーブルメンテナンス - 自動メンテナンス操作について
- R2 Data Catalog - 概要と開始ガイド
- データをクエリする - R2 SQL でテーブルをクエリする
- Apache Iceberg Maintenance ↗ - テーブルメンテナンスに関する公式 Iceberg ドキュメント
-
タイムトラベルは
expire_snapshotsを呼び出すまで利用できます ↩