🎓 レベル:発展 | 重要度:B(推奨)
📎 前提:列指向ストレージと分析クエリ | 関連:データレイクとオブジェクトストレージ・レイクハウスとテーブルフォーマット
要点(BLUF)
- データをファイルに落とす(シリアライズする)形式は複数ある。CSV/JSONは人が読めるが大きく型が曖昧。Parquet/ORCは列指向・高圧縮・スキーマ同梱で分析向き。Avroは行指向でスキーマ進化に強くストリーム向き。
- 分析(一括書き・大量読み・集計)には Parquet が事実上の標準。来た端から1件ずつ書くストリームには Avro。
- 選択軸は (1) 列指向か行指向か(読み方)/(2) 圧縮効率/(3) スキーマを持つか・進化に強いか。この領域はエコシステムの動きが速いので要最新確認。
概念 ── 「どう並べて、どう書き出すか」
シリアライゼーションとは、メモリ上のデータ(テーブル・オブジェクト)をファイルやネットワークに流せるバイト列に変換すること。逆がデシリアライズ。CSVもParquetも「テーブル→バイト列」の方法ですが、並べ方(行/列)・圧縮・スキーマの持ち方が違い、それが性能と運用を大きく分けます。
flowchart TB
CSV["CSV / JSON:人間可読・行指向・型曖昧・大きい"]
AVRO["Avro:行指向・スキーマ同梱・進化に強い・ストリーム向き"]
PARQ["Parquet / ORC:列指向・高圧縮・統計付き・分析向き"]
仕組み ── 三つの軸で比べる
| 形式 | 並べ方 | 圧縮 | スキーマ | 得意 |
|---|---|---|---|---|
| CSV | 行 | ほぼなし | なし(全部文字列) | 受け渡し・少量・目視 |
| JSON | 行(入れ子可) | ほぼなし | なし(自己記述的) | API・半構造データ |
| Avro | 行 | あり | ファイルに同梱・進化に強い | ストリーム・取り込み |
| Parquet | 列 | 高い(列ごと) | 同梱・統計付き | 分析・DWH・レイク |
| ORC | 列 | 高い | 同梱・統計付き | 分析(Hadoop系) |
- スキーマ同梱:Parquet/Avroはファイル自身が列名・型を持つ。CSVは持たないため、読む側が毎回「この列は数値」と推測/指定する必要があり事故のもと。
- スキーマ進化:Avroは「列の追加・削除・既定値」を後方/前方互換のルールで扱える。源の形が変わり続けるストリームに向く。
- 列統計:Parquetは列ブロックごとに min/max を持ち、不要ブロックをスキップ(述語プッシュダウン)。
動くSQL/変換例 ── CSV vs Parquet を実測
同じ5万行を CSV と Parquet で書き出し、サイズと「1列だけ読む」を比べます。
import pandas as pd
df = pd.DataFrame({"id": range(50000),
"region": ["East","West","North","South"]*12500,
"amount": [(i*7) % 1000 for i in range(50000)]})
df.to_csv("data.csv", index=False)
df.to_parquet("data.parquet", index=False) # pyarrow + snappy 圧縮
only = pd.read_parquet("data.parquet", columns=["amount"]) # 必要列だけ読む
print(int(only["amount"].sum()))
実行結果(実機):
行数: 50000
CSV : 789.5 KB
Parquet : 305.4 KB (圧縮率 2.6 倍)
Parquetから amount 列だけ読込 -> shape=(50000, 1), 合計=24975000
Parquetは同じデータでCSVの約2.6分の1のサイズ(regionのような繰り返し文字列がよく圧縮される)。さらに columns=["amount"] で他の列を一切読まずに合計を計算できます。これが 列指向ストレージと分析クエリ の「必要な列だけI/O」の実物です。
なぜそうするか ── 読み方に形式を合わせる
なぜ「分析はParquet、ストリームはAvro」なのか。データの使われ方に物理形式を合わせるのが原則だからです。分析は「大量行・少数列・一括書き」なので、列指向で高圧縮なParquetが最適。ストリーム取り込みは「1件ずつ来る・全列まとめて書く・スキーマが進化する」ので、行指向でスキーマ進化に強いAvroが向く。CSVは「とりあえず受け渡す」用途には便利でも、型が無く圧縮も効かないため、基盤の中核に据えると後で苦労します。
⚠️ よくある落とし穴
- 基盤の保存形式にCSVを使い続ける → 型崩れ(先頭ゼロ・日付・桁あふれ)と肥大化。レイク/DWHの保存はParquet系へ。
- Parquetに1件ずつ追記しようとする → 列指向は一括書き前提。小ファイル乱立(small files problem)で逆に遅くなる。まとめて書く。
- 圧縮形式(snappy/zstd/gzip)を無頓着に選ぶ → snappyは速いが圧縮弱め、zstdは高圧縮。用途で選ぶ。
- スキーマ進化を考えずに列を消す → 古いファイルが読めなくなる。Avro/テーブルフォーマットの進化ルールに従う(→ レイクハウスとテーブルフォーマット)。
対応ラボ
data-engineering-study/labs/03_sql_optimization.py(PYTHONIOENCODING=utf-8 で実行・CSV/Parquetサイズと列読みを確認済み)。
関連
- 列指向が速い理屈は 列指向ストレージと分析クエリ
- これらのファイルを置く場所は データレイクとオブジェクトストレージ
- ファイル群に表の機能(更新・タイムトラベル)を足すのが レイクハウスとテーブルフォーマット