---
title: マイクロアドのData LakehouseとIcebergテーブルの最適化について
tags:  #data  
author: [やっさん🍶](https://convert.docswell.com/user/yassan)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/VENY5592J8.jpg?width=480
description: 2025-06-17 OTFSG Osaka Meetup #01 https://otfsg-tokyo.connpass.com/event/352637/
published: June 17, 25
canonical: https://convert.docswell.com/s/yassan/537P42-otfsg-osaka-01
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/VENY5592J8.jpg)

2025-06-17：OTFSG Osaka Meetup #01
#otfsg_tokyo
マイクロアドのData Lakehouseと
Icebergテーブルの最適化について
株式会社マイクロアド
永富 安和 ( @yassan168 )


# Page. 2

![Page Image](https://bcdn.docswell.com/page/Y79PYY2DE3.jpg)

アジェンダ
1. マイクロアドのデータ基盤について
2. Icebergテーブルの概要 ちょっとだけ⋯
3. Icebergテーブルの最適化に関する話
4. まとめ
#trinodb


# Page. 3

![Page Image](https://bcdn.docswell.com/page/G78D66557D.jpg)

マイクロアドについて


# Page. 4

![Page Image](https://bcdn.docswell.com/page/L7LM99Y3JR.jpg)

マイクロアドが提供する事業
#trinodb
自社製品である 「データプロダクト」 と、
主に 他社製品を扱う 「コンサルティング」の二つの事業
※2025年9月期 決算説明資料より抜粋


# Page. 5

![Page Image](https://bcdn.docswell.com/page/4EMYZZNMEW.jpg)

データプロダクト「UNIVERSE」について
#trinodb
膨大なデータから業界業種毎の消費行動プロセスの違いを分析することで、
特定の製品カテゴリ毎に比較検討を開始したユーザ、最終的な購買検討段階に
移行したユーザー、購買意欲が急激に高まった瞬間など、
個人の製品認知・購買プロセスの段階に応じたより効果的な広告配信を実現
※1 2024年9月実績
※2 RTB： Real Time Biddingの略称


# Page. 6

![Page Image](https://bcdn.docswell.com/page/PER966DLJ9.jpg)

マイクロアドのデータ基盤について


# Page. 7

![Page Image](https://bcdn.docswell.com/page/P7XQMM26EX.jpg)

これまでのデータ基盤の概要
実効容量
約13T
B/day
を処理
ト
イ
バ
タ
約2ペ
分析クエリ実行
参照
平均流量は
Gbit/sec
Impala
参照
分析用クラスタ
Data Lake
Streaming
ログ転送
書き
込み
バッチ
実行
HDFSをHiveの
定
Locationに指
広告配信サーバ
各種サーバ
Spark Streaming
（リアルタイム加工）
Redis
ワークフロー
バッチ
実行


# Page. 8

![Page Image](https://bcdn.docswell.com/page/37K9GGMG7D.jpg)

今回の刷新範囲
分析クエリ実行
ココ！
参照
Impala
参照
分析用クラスタ
Data Lake
Streaming
ログ転送
書き
込み
バッチ
実行
バッチ
実行
広告配信サーバ
各種サーバ
Spark Streaming
（リアルタイム加工）
Redis
ワークフロー


# Page. 9

![Page Image](https://bcdn.docswell.com/page/LJ3WNNY5J5.jpg)

これまでのデータ基盤の課題
#trinodb
1. 利用しているHadoopディストリビューションが継続利用出来ない
○
有償のCloudera CDPも検討したが費用面がクリア出来ず見送り
（PaaSも色々検討したが費用や技術課題がクリア出来ず見送り。5年償却で見たクラウドは高い）
2. レプリカ３が結構にコストに直結
○
実効容量２PBということは、物理Diskで６PBは必要な現実
○
Hadoop 3.x なら Erasure Coding もあるけど、
ディスク消費を抑えやすいが CPU 使用率が増える問題
3. 実質的に Compute と Storage を切り離してスケールしづらい
○
○
NodeManager と DataNode は 同居が前提（データ局所性）
→ ノード追加＝CPU＋ディスク丸ごと増量
専用 Computeノードも構築可能だがデータ転送増＆帯域ボトルネックで割に合わない


# Page. 10

![Page Image](https://bcdn.docswell.com/page/8JDKWW5YEG.jpg)

これまでのデータ基盤の課題
4. Impalaの統計情報の運用が非常に煩雑かつ有効に利用出来ない
○
ワイドカラム・大量データの大規模テーブルの場合、ほぼ使えない
(inc_stats_size_limit_bytesを大きく設定できない問題)
○
統計情報が不十分なので効率の悪いクエリになりがち
5. ETL/ELT処理は Hive on MapReduce なので確実に処理するが遅い
○
Tez・LLAPを使うべきだがHiveが古くて利用できない
6. Hive Metastore が大量パーティションで悲鳴を上げる
○
大量の DROP PARTITION / DROP TABLE が メタストア DB ロックを長時間保持
○
Metastore Thrift サーバーが フル GC → 接続タイムアウト を誘発
7. テーブル構造が複雑でSQLベースでETL/ELT処理するのが辛い
○
複雑なクエリになりがちで、改修に難易度が高く手間がかかる
#trinodb


# Page. 11

![Page Image](https://bcdn.docswell.com/page/VEPK99G278.jpg)

新しいデータ基盤に求める事
#trinodb
1. ComputeとStorageを分離できる事
2. ETL/ELT処理はSQLだけでなくコードベースで処理したい
3. 大規模なテーブルでも統計情報を更新・有効活用できる事
4. Hiveの様にオンラインで柔軟なスキーマ進化が可能である事


# Page. 12

![Page Image](https://bcdn.docswell.com/page/27VVMM6X7Q.jpg)

MDP(Microad Data Platform) Overview
分析クエリ
REST Catalog
Server
R/W
(Active/Standby)
(Active/Standby)
管理
管理
Sparkアプリをapply
Spark Connect
で接続して処理
R/W
DELL ECS(S3互換ストレージ)
Sparkアプリの
リソース制御


# Page. 13

![Page Image](https://bcdn.docswell.com/page/5JGLGGNR7L.jpg)

ざっくりな使い分け
Ad-hoc
クエリ
Business User
Engineer
Digdag
Redash
Trino Gateway
Spark Connect Client
Trino on K8s
Coordinator
Iceberg REST Catalog
ETL/ELT処理
Gateway
Layer
Spark Operator
Spark on K8s
Worker
SparkApp
SparkApp
Catalog Layer
Spark Connect
Server
SparkApp
SparkApp
SparkApp
Dell ECS（S3-Compatible）
Compute
Layer
Storage Layer


# Page. 14

![Page Image](https://bcdn.docswell.com/page/47QYXXQYEP.jpg)

得られた効果


# Page. 15

![Page Image](https://bcdn.docswell.com/page/KE4W66NZJ1.jpg)

得られた効果
#trinodb
1. ComputeとStorageを分離出来る事
😆 ComputeはSpark・Trino、Storageは S3互換ストレージと明確に分離出来た
😆 YARN・Zookeeperの依存がなくなり構成要素が減った
2. ETL/ELT処理はSQLだけでなくコードベースで処理したい
😆 SQLでは表現しづらい複雑なビジネスロジックをPySparkのDataFrame APIで
柔軟に実装可能になった


# Page. 16

![Page Image](https://bcdn.docswell.com/page/L71YVV5DJG.jpg)

得られた効果
#trinodb
3. 大規模なテーブルでも統計情報を更新・有効活用ができる事
😆 Icebergテーブルを使うことで、Impalaで問題になっている統計情報が作れな
い問題が発生しない
■ パーティション情報といった基本的な統計情報は
テーブル書き込み時に意識せずに作成が可能になった
■ 実行エンジン側で柔軟に統計情報の更新も可能
4. Hiveの様にオンラインで柔軟なスキーマ進化が可能である事
😆 Iceberg特有のスキーマ進化（or パーティション進化）により、
以前より柔軟な運用が選択可能になった


# Page. 17

![Page Image](https://bcdn.docswell.com/page/G7WGLL58E2.jpg)

Apache Icebergテーブルについて


# Page. 18

![Page Image](https://bcdn.docswell.com/page/4JZLMMN9E3.jpg)

Apache Icebergとは
#trinodb
Netﬂix、Apple、Tencent、Pinterest などの多くの大企業も本番利用している
巨大で複雑なデータセットにも対応可能なOpen Table Formatの1つ。
特徴
● 複数のエンジンから同じテーブルを操作できる
○
例：Spark・Flink・Trino・Presto・Hive・Impala
● 安全なテーブル操作
○
ACIDなコミット（Atomic Commit + Optimistic Concurrency）
● スキーマ／パーティション進化
○
既存データをコピーせず列やパーティションを変更
● Hidden Partitioning
○
パーティションを意識せずにクエリしたり、パーティションレイアウトを変更可能
● タイムトラベル／ロールバック
○
“過去の状態” でクエリ／ロールバックが可能


# Page. 19

![Page Image](https://bcdn.docswell.com/page/YE6WNN8DEV.jpg)

”Iceberg”＝仕様だけ ― 実装はエンジン &amp; SDK が担
#trinodb
当
言わば、Iceberg はデータ版 HTTPの様なもの。
● HTTP：プロトコル仕様だけを定め、Apache/Nginx/Chrome が実装
● Iceberg：テーブル仕様 だけを定め、Spark/Trino/PyIceberg … が実装
つまり、、、
「”Iceberg” という振る舞い」をテーブル仕様に基づき独自に実装
テーブル仕様は公開され・コミュニティで仕様を決定しているので、
様々な実行エンジン＆各言語SDKによりIcebergテーブルに対して操作が可能。
＝ベンダーロックインがない。
とは言え、、
きたけど、
ダーロックインは回避で
ン
ベ
eの
ut
mp
Co
eや
ag
or
St
ようとする動きが、、、
し
ン
イ
ク
ッ
ロ
で
グ
ロ
タ
今度は各社カ


# Page. 20

![Page Image](https://bcdn.docswell.com/page/GE5M5598E4.jpg)

Icebergテーブルのアーキテクチャ
大きく３つに構成されます。
1. カタログ
2. メタデータ層
3. データ層
今回は、３→2→1 の順で、
下から順に説明していきます。
#trinodb


# Page. 21

![Page Image](https://bcdn.docswell.com/page/9729NN2VJR.jpg)

⚠ ここから先は Icebergテーブル仕様 v2 を前提とします
すま
ん...
尺が足りないので割愛。
以下で説明してます！
Icebergテーブルの内部構造について - やっさんメモ


# Page. 22

![Page Image](https://bcdn.docswell.com/page/DJY4PPYQ7M.jpg)

Icebergテーブル：データ層
以下の３つで構成
●
●
●
データファイル
削除ファイル
Puﬃnファイル
データ層は、分散ファイルシステム（HDFS）
や、オブジェクトストレージに対応。
#trinodb


# Page. 23

![Page Image](https://bcdn.docswell.com/page/V7NY55P2E8.jpg)

Icebergテーブル：データ層
データファイル
テーブルのデータそのもの。
Parquet・Avro・Orcに対応。
※同一テーブル中に複数のフォーマットでもアリ
削除ファイル
テーブルのデータセット内の どのレコードが
削除されたかを追跡する際に利用。
以下の2種類の戦略がある。
● Copy-On-Write(CoW)
● Merge-On-Read(MoR)
#trinodb


# Page. 24

![Page Image](https://bcdn.docswell.com/page/YJ9PYY3D73.jpg)

Icebergテーブル：データ層
Puﬃnファイル
データファイルやメタデータファイルに格
納される統計情報よりも更に
幅広いクエリのパフォーマンスを
向上させるデータテーブル内のデータに関
する統計情報とインデックスを格納。
#trinodb


# Page. 25

![Page Image](https://bcdn.docswell.com/page/GJ8D66M5JD.jpg)

Icebergテーブル：メタデータ層
以下の３つで構成され、ツリー構造になっ
ている。
● メタデータファイル
● マニフェストリスト
● マニフェストファイル
#trinodb


# Page. 26

![Page Image](https://bcdn.docswell.com/page/LJLM9933ER.jpg)

Icebergテーブル：メタデータ層
マニフェストファイル
データ層内のファイルの追跡と、各ファイルに
関する追加の詳細や統計情報を保持。
１つのマニフェストファイルには、
１つの「データファイル」または
「削除ファイル」のみが含まれる。
各マニフェストファイルには、以下が含まれる
●
●
●
●
パーティションのどこに紐づいているか
レコード数
カラムの上限と下限値
etc..
は
ファイル名
o
r
***.av
#trinodb


# Page. 27

![Page Image](https://bcdn.docswell.com/page/47MYZZDM7W.jpg)

Icebergテーブル：メタデータ層
マニフェストリスト
マニフェストファイルのリスト。
マニフェストリストには、テーブルのある時点での
状態である「スナップショット」を構成する
各マニフェストファイルに関する情報がある。
は
その情報には、以下が含まれます。
ファイル名
vr
a
.
*
*
snap-*
● マニフェストファイルのパス
o
● どのスナップショットの一部として
追加されているのか
● 属するパーティションに関する情報
● 追跡するデータファイルのパーティション列の
下限と上限値
#trinodb


# Page. 28

![Page Image](https://bcdn.docswell.com/page/P7R9664LE9.jpg)

Icebergテーブル：メタデータ層
メタデータファイル
テーブルに関するメタデータを格納し、
以下の情報が含まれています。
● テーブルのスキーマ
● パーティション情報
● スナップショット
● 現状のスナップショットはどれか
Icebergテーブルが変更されるたびに
新しいメタデータファイルが作成されます。
また、次に説明するカタログにより
アトミックに最新版のメタデータファイル
として登録される。
は
ファイル名 .jso
ta
a
d
a
t
v⃝.me
n
または
m-uuid&gt;
⃝-&lt;rando
.json
.metadata
#trinodb


# Page. 29

![Page Image](https://bcdn.docswell.com/page/PJXQMMZ67X.jpg)

Icebergテーブル：カタログ
カタログ
最新のメタデータがどこにあるかを保持する。
その為、カタログの主な要件は、現在のメタ
データのポインタを更新するためのアトミック
な操作をサポートすることにある。
カタログには色々な実装があります。
● Hadoopカタログ(File System)
● Hiveカタログ
● Nessieカタログ
● AWS Glueカタログ
● RESTカタログ
#trinodb


# Page. 30

![Page Image](https://bcdn.docswell.com/page/3JK9GG8GJD.jpg)

メタデータ層の動きについて
な
の話
ここ


# Page. 31

![Page Image](https://bcdn.docswell.com/page/LE3WNN25E5.jpg)

テーブル作成直後（おさらい）
カタログ
ice.tbl1
メタデータ層
データ層
metadata ﬁle
manifest list
manifest
v⃝.metadata.json
snap-***.avro
***.avro
v1.json
● テーブルのスキーマ情報
● パーティション情報
● スナップショット情報や履歴
● テーブルのプロパティ
メタデータファイル
＝「テーブル全体の現行設定とスナップショット一覧を管理」
💡カタログで管理してるのは、こいつの最新のパス
スナップショット
＝「ある時点でのテーブルの全体像（＝ データファイルの集合）」
💡タイムトラベル／ロールバック単位。


# Page. 32

![Page Image](https://bcdn.docswell.com/page/8EDKWWZY7G.jpg)

メタデータはツリー構造（おさらい）
カタログ
ice.tbl1
メタデータ層
データ層
metadata ﬁle
manifest list
manifest
v⃝.metadata.json
snap-***.avro
***.avro
v1.json
s1
Snapshotの s
m1 stats
m1
A metadata
A.parquet
B metadata
● マニフェストファイルのパス
● どのスナップショットの一部として追加されているのか
● 属するパーティションに関する情報
● 追跡するデータファイルのパーティション列の下限と上限値
B.parquet
マニフェストリスト
＝「スナップショットが参照するマニフェストファイルのリスト」
💡このスナップショットに何が入ってるの？を高速に把握


# Page. 33

![Page Image](https://bcdn.docswell.com/page/V7PK99D2J8.jpg)

メタデータはツリー構造（おさらい）
カタログ
ice.tbl1
メタデータ層
データ層
metadata ﬁle
manifest list
manifest
v⃝.metadata.json
snap-***.avro
***.avro
v1.json
manifest
の m
s1
m1 stats
m1
A metadata
A.parquet
B metadata
B.parquet
● パーティションのどこに紐づいているか
● レコード数
● カラムの上限と下限値
マニフェストファイル
＝「データファイルのメタ情報（パーティション値・列統計など）」
💡スキャン計画時に不要ファイルを即座に除外


# Page. 34

![Page Image](https://bcdn.docswell.com/page/2JVVMM1XJQ.jpg)

データを挿入（書き込み中）
カタログ
ice.tbl1
メタデータ層
データ層
metadata ﬁle
manifest list
manifest
v⃝.metadata.json
snap-***.avro
***.avro
v1.json
s1
m1 stats
m1
A metadata
A.parquet
B metadata
B.parquet
C metadata
C.parquet
s1
v2.json
s2
m1 stats
m2 stats
m2
まずは実行エンジン側で書き込
み


# Page. 35

![Page Image](https://bcdn.docswell.com/page/5EGLGG2RJL.jpg)

データを挿入（書き込み完了）
カタログ
ice.tbl1
メタデータ層
metadata ﬁle
manifest list
manifest
v⃝.metadata.json
snap-***.avro
***.avro
v1.json
s1
m1 stats
最新のパス
を切り替え
ice.tbl1
データ層
m1
A metadata
A.parquet
B metadata
B.parquet
C metadata
C.parquet
s1
v2.json
s2
m1 stats
m2 stats
m2
📑同時書き込み制御の話はべりんぐさんのブログがとても参考になりま
す！
Apache Icebergの同時実行制御における競合解決の仕組みと注意点
https://bering.hatenadiary.com/entry/2025/01/18/234339


# Page. 36

![Page Image](https://bcdn.docswell.com/page/4JQYXXPY7P.jpg)

Icebergテーブルのメンテナンス


# Page. 37

![Page Image](https://bcdn.docswell.com/page/K74W66YZE1.jpg)

なぜIcebergテーブルにメンテナンスが必要？
よくある “詰まり” シナリオ
● 高頻度アップサート／ストリーム書込み
→ マニフェストが爆増して プランニング遅延
● 小さなバッチ Insert が続く
→ “Smallファイル問題” で I/O 効率 ↓↓↓
● 分析速度を上げるための並べ替え（ソート/クラスタリング）
→ 既存ファイルを再編成しない限り効果が出ない
放置すると...
1. Query Planning が遅い
○ 1 クエリで数千 manifest を開く事態も
2. スキャン効率 &amp; 物理コストが悪化
○ S3 API コール増加 / キャッシュ不可ファイル増殖
#trinodb


# Page. 38

![Page Image](https://bcdn.docswell.com/page/LJ1YVV6DEG.jpg)

なぜIcebergテーブルにメンテナンスが必要？
よくある “詰まり” シナリオ
● 高頻度アップサート／ストリーム書込み
→ マニフェストが爆増して プランニング遅延
● 小さなバッチ Insert が続く
→ “Smallファイル問題”
で I/O 効率 ↓↓↓
なので、メタデータ層・データ層において
● 分析速度を上げるための並べ替え（ソート/クラスタリング）
→ 既存ファイルを再編成しない限り効果が出ない
”定期的なお掃除”が必要！
放置すると...
1. Query Planning が遅い
○ 1 クエリで数千 manifest を開く事態も
2. スキャン効率 &amp; 物理コストが悪化
○ S3 API コール増加 / キャッシュ不可ファイル増殖
#trinodb


# Page. 39

![Page Image](https://bcdn.docswell.com/page/GJWGLLW872.jpg)

📑以降はSparkのプロシージャを例に解説していきま
す
データ層の整理


# Page. 40

![Page Image](https://bcdn.docswell.com/page/4EZLMM5973.jpg)

データファイルのCompaction（rewrite_data_ﬁles）
カタログ
メタデータ層
データ層
metadata ﬁle
manifest list
manifest
rewrite_data_ﬁles前
v⃝.metadata.json
snap-***.avro
***.avro
データサイズがとて
も小さい
v1.json
or ソートされてないとする
s1
m1 stats
m1
ice.tbl1
A metadata
A.parquet
B metadata
B.parquet
C metadata
C.parquet
s1
v2.json
s2
m1 stats
m2 stats
m2


# Page. 41

![Page Image](https://bcdn.docswell.com/page/Y76WNN9D7V.jpg)

データファイルのCompaction（rewrite_data_ﬁles）
カタログ
メタデータ層
metadata ﬁle
manifest list
rewrite_data_ﬁles後
v⃝.metadata.json
snap-***.avro
v1.json
s1
データ層
manifest
ファイルの最適化
***.avro
（小さいファイルをまとめた
り、ソートし直す）
m1 stats
m1
A metadata
A.parquet
B metadata
B.parquet
C metadata
C.parquet
s1
v2.json
s2
m1 stats
m2 stats
m2
s1
ice.tbl1
v3.json
s2
s3
m2 stats
NEW
m3 stats
m3
NEW
AB metadata
AB.parquet


# Page. 42

![Page Image](https://bcdn.docswell.com/page/G75M55N874.jpg)

データファイルのCompaction
#trinodb
行レベル削除ファイル（Position Delete）のコンパクション
rewrite_position_delete_ﬁles
● merge-on-read （MoR） モードで増える小粒 Position Delete をま
とめ、
○ 目標サイズ（既定 64 MB）で再書き出し
○ 「宙ぶらりん（dangling）」 な delete 行も同時に除去
● Position Deleteは Icebergテーブル仕様 v3 では非推奨
（新規追加は禁止／既存は読み取り可）
○ 後継は Deletion Vectors (DV)


# Page. 43

![Page Image](https://bcdn.docswell.com/page/9J29NN5VER.jpg)

日時キー付きテーブルの「不要データ」の削除
#trinodb
勘違いしやすいやつの１つ。
スナップショットを期限切れにしたところでレコードは削除されない。
Iceberg は 自動 TTL を持たない。
古データを捨てるには 2 段階で手動実行が必要
1. DELETE文で論理削除
○
-- 90日前のレコードは削除
DELETE FROM c.ns.tbl WHERE event_date &lt; date_sub(current_date, 90);
2. Deleteされて紐づかなくなったスナップショットをexpire_snapshotsする
ことでファイルを物理削除


# Page. 44

![Page Image](https://bcdn.docswell.com/page/DEY4PPKQJM.jpg)

メタデータ層の整理


# Page. 45

![Page Image](https://bcdn.docswell.com/page/VJNY55R278.jpg)

メタデータのCompaction（expire_snapshots）
カタログ
メタデータ層
metadata ﬁle
manifest list
v⃝.metadata.json
snap-***.avro
v1.json
データ層
expire_snapshots前
manifest
***.avro
s1
m1 stats
m1
A metadata
A.parquet
B metadata
B.parquet
C metadata
C.parquet
AB metadata
AB.parquet
s1
v2.json
v3 の時点では s1 や s2
に戻ることは出来る
ice.tbl1
v3.json
最新は
こっち
s2
m1 stats
m2 stats
m2
s1
s2
m2 stats
s3
m3 stats
m3


# Page. 46

![Page Image](https://bcdn.docswell.com/page/YE9PYYMDJ3.jpg)

メタデータのCompaction（expire_snapshots）
カタログ
メタデータ層
metadata ﬁle
manifest list
v⃝.metadata.json
snap-***.avro
v1.json
データ層
expire_snapshots後
manifest
***.avro
s1
m1 stats
m1
s1
v2.json
s2
A metadata
A.parquet
B metadata
B.parquet
C metadata
C.parquet
AB metadata
AB.parquet
m1 stats
s1
v3.json
s1やs2を期限切れに
して整理する
m2 stats
s2
m2
s3
m2 stats
ice.tbl1
v4.json
s3
m3 stats
m3


# Page. 47

![Page Image](https://bcdn.docswell.com/page/GE8D66L5ED.jpg)

メタデータのCompaction（expire_snapshots）
カタログ
メタデータ層
データ層
metadata ﬁle
manifest list
manifest
v⃝.metadata.json
snap-***.avro
***.avro
v1.json
s1
m1 stats
m1
s1
v2.json
s2
A metadata
A.parquet
B metadata
B.parquet
C metadata
C.parquet
AB metadata
AB.parquet
m1 stats
s1
v3.json
m2 stats
s2
m2
s3
m2 stats
ice.tbl1
v4.json
s3
m3 stats
m3


# Page. 48

![Page Image](https://bcdn.docswell.com/page/LELM99L37R.jpg)

メタデータファイルはいつ消えるの？
カタログ
メタデータ層
データ層
metadata ﬁle
manifest list
manifest
v⃝.metadata.json
snap-***.avro
***.avro
v1.json
s1
s1
v2.json
s2
テーブルプロパティを以下にするとメタデータファイルを削除
出来る（＝指定しないと消えない）
&#039;write.metadata.delete-after-commit.enabled&#039; = &#039;true&#039;
最大何個 残すかは以下で指定
‘write.metadata.previous-versions-max’ = 100
s1
v3.json
m2
s2
C metadata
C.parquet
AB metadata
AB.parquet
s3
m2 stats
ice.tbl1
v4.json
s3
m3 stats
m3


# Page. 49

![Page Image](https://bcdn.docswell.com/page/4JMYZZMMJW.jpg)

メタデータのCompaction（rewrite_manifests）
カタログ
メタデータ層
metadata ﬁle
manifest list
v⃝.metadata.json
snap-***.avro
データ層
rewrite_manifests
manifest
前
***.avro
m2
ice.tbl1
v4.json
m3 stats
C.parquet
例えば、どちらも同じ
パーティション内のデータ
m2 stats
s3
C metadata
m3
AB metadata
AB.parquet


# Page. 50

![Page Image](https://bcdn.docswell.com/page/PJR966VL79.jpg)

メタデータのCompaction（rewrite_manifests）
カタログ
メタデータ層
metadata ﬁle
manifest list
manifest
v⃝.metadata.json
snap-***.avro
***.avro
m2
データ層
rewrite_manifests
後
C metadata
C.parquet
AB metadata
AB.parquet
m2 stats
v4.json
ice.tbl1
v5.json
s3
m3 stats
s3
s4
m3
m4
m4 stats
ABC metadata
データはそのままで
新しいマニフェストから
どちらのデータも指す


# Page. 51

![Page Image](https://bcdn.docswell.com/page/PEXQMMW6JX.jpg)

他にも、、
#trinodb
孤立ファイルのクリーンアップ (remove_orphan_ﬁles)
●
●
●
メタデータに参照されない orphan ﬁle （孤児ファイル）を物理削除
既定で 3 日より古いファイルのみ 対象
older_than でデフォルト「3日」から調整は可能
注意点
●
別でデータ書き込み中のファイルが remove_orphan_ﬁles の
対象期間中だった場合、誤って削除する可能性があるので、ワークロードに
合わせた older_than の設定が重要
○
実行時には戻り値の orphan_ﬁle_location をログ出力しておいて、何を削除したのか追跡可
能にしておくと安心


# Page. 52

![Page Image](https://bcdn.docswell.com/page/3EK9GGVGED.jpg)

問題です！！！
どの順で実行するとコスパが良いでしょうか？
1. delete from c.ns.tbl where ** (要らなくなったレコードの削除)
2. remove_orphan_ﬁles
3. rewrite_data_ﬁles
4. rewrite_position_delete_ﬁles
5. rewrite_manifests
6. expire_snapshots
#trinodb


# Page. 53

![Page Image](https://bcdn.docswell.com/page/L73WNNM575.jpg)

正解は、、、 （多分だけどな）
#trinodb
1. 古いレコードの削除
delete from c.ns.tbl where **
2. データの最適化（適正サイズ化・ソート）
rewrite_data_ﬁles / rewrite_position_delete_ﬁles
3. マニフェストの最適化
rewrite_manifests
4. スナップショットをGC
づく
期限切れのスナップショットに紐
削除
要らないデータやマニフェストも
expire_snapshots
5. メタデータのどこにも紐づいていないファイルの削除
remove_orphan_ﬁles


# Page. 54

![Page Image](https://bcdn.docswell.com/page/87DKWW6YJG.jpg)

注意点
●
#trinodb
データまたはメタデータを整理に伴い、コミットが発生するので、
対象が他メンテナンス処理含む全てのデータ更新と重複させない対策が必要
（被ったらプロシージャが失敗する）
例えば、以下のプロシージャのパラメータ older_than を使って対象期間を
指定出来る
○ remove_orphan_ﬁles（孤児ファイルの削除）
○ expire_snapshots （スナップショットのGC）
● データのソートやクラスタリングは慎重に選ばないと、デカいテーブル
程、やり直しにはかなりの計算コストが必要になるので注意して検討が
必要


# Page. 55

![Page Image](https://bcdn.docswell.com/page/VJPK99Y2E8.jpg)

悩みのタネ — みなさんどうしてますか？
カラムの統計ってどうしてますか？
min / max / null_count はテーブル書き込み時に作成済みだけど、、
compute_table_stats 使ってNDV (distinct_count)作成してますか？
●
●
かなりの計算コストを支払うので、そこまでやるメリットがどれくらいあるのか？
○ 追記/削除が多いテーブルはNDV が陳腐化するから再計算も必要になる
高カーディナリティになりがちのSTRING型カラムは含めてますか？
Icebergテーブルの最適化のタイミングの決定する基準は？
● 一律 1日1回とか？
● remove_orphan_ﬁles と expire_snapshots
の older_than ってどうしてます？
#trinodb


# Page. 56

![Page Image](https://bcdn.docswell.com/page/2EVVMMGXEQ.jpg)

まとめ


# Page. 57

![Page Image](https://bcdn.docswell.com/page/57GLGG8REL.jpg)

まとめ
● マイクロアドのData Lakehouse事例紹介
● Icebergテーブルについて
● Icebergテーブルの最適化について
#trinodb


# Page. 58

![Page Image](https://bcdn.docswell.com/page/4EQYXX9YJP.jpg)

参考
●
#trinodb
Apache Iceberg とは何か - Bering Note – formerly 流沙河鎮
https://bering.hatenadiary.com/entry/2023/09/24/175953
●
Icebergテーブルの内部構造について - やっさんメモ
https://yassan.hatenablog.jp/entry/advent-calendar-2023-1201
●
Apache Iceberg&#039;s Best Secret: A Guide to Metadata Tables - YouTube
https://www.youtube.com/watch?v=4K0HBWUIEKI
●
Apache Icebergの同時実行制御における競合解決の仕組みと注意点 - Bering
Note – formerly 流沙河鎮
https://bering.hatenadiary.com/entry/2025/01/18/234339
●
Lakehouse テーブル形式とカタログの活用 | データエンジニアリング オープ
ンフォーラム 2025 - YouTube
https://youtu.be/wLsMrdfBuwU?si=4lrh8Ds2HV6EmN7s
●
ダ鳥獣戯画
https://chojugiga.com/


# Page. 59

![Page Image](https://bcdn.docswell.com/page/KJ4W66XZ71.jpg)



