Parquet とは何なのか。その真価は不要なデータを読み飛ばせることにあり

記事タイトルとURLをコピーする

Parquet って何者? 何が嬉しいの?

Amazon Athena について調べていると、「Parquet のような列指向形式でデータを保存するとクエリ効率を上げることができる」というような文言を目にしました。

Parquet 形式で保存すると列指向で速いんだなぁ。

そんな程度に思っていたのですが、じゃあ「どうして列指向だとクエリ効率が良くなるのか」、「実際どれくらい速くなるのか」が気になったので深掘りしてみました。

この記事の対象者

  • Parquet、列指向データ形式って何?という状態の人
  • CSV などの一般的なテキストデータ (行指向) と Parquet (列指向) の違いを知りたい人
  • Parquet がどんなケースで適しているのか知りたい人
  • 実際どれくらいクエリ効率に影響があるのかが気になる人

簡単要約

  • Parquet はデータを列ごとに保存する 「列指向」 フォーマット
  • Amazon Athena では、列指向にすることで 「圧縮が効く」「不要な列を読まない」「並列処理しやすい」 というメリットがある
  • その結果、クエリが速くなり、スキャンデータ量が減ることでコストも安くなる
  • AWS 公式の比較でも、実行時間・コスト共に 90%近い改善 が紹介されている

Parquet 形式とは。CSV との保存イメージの違い

Apache Parquet とは、効率的なデータの保存と取得を目的として設計されたオープンソースの 「列指向」 のデータファイル形式です。

読み方は「パーケ」「パーケット」「パルケ」などと読み、フランス語で寄木を意味するそうです。

一方、CSV のようなテキストファイルは 「行指向」 のデータ形式です。

列指向と行指向の違いを、以下の仮想ユーザーテーブルを例に見てみましょう。

ID 名前 年齢 性別 居住地
1 佐藤 18 男性 北海道
2 鈴木 29 女性 大阪府
3 高橋 50 女性 岡山県
4 田中 90 男性 滋賀県
5 伊藤 5 男性 三重県

CSV (行指向) の保存イメージ

このテーブルを CSV 形式で保存すると、以下のように 行ごとにデータが保存 されます。

1,佐藤,18,男性,北海道
2,鈴木,29,女性,大阪府
3,高橋,50,女性,岡山県
4,田中,90,男性,滋賀県
5,伊藤,5,男性,三重県

各行には、ID、名前、年齢、性別、居住地といった 複数の列 のデータが含まれています。

Parquet (列指向) の保存イメージ

一方、Parquet 形式で保存すると、以下のように 列ごとにデータが保存 されます。

※ あくまでイメージです。実際にはバイナリ形式で列ごとに圧縮された状態で保存されるので、このようにテキストとしては表現されません。

1,2,3,4,5
佐藤,鈴木,高橋,田中,伊藤
18,29,50,90,5
男性,女性,女性,男性,男性
北海道,大阪府,岡山県,滋賀県,三重県

このように、行指向データでは 各行 が一つのレコードとして保存されるのに対し、列指向データでは 列単位 でデータがまとめて保存されるんですね。

この違いが、クエリ効率に大きな影響を与えます。

平均年齢を計算する場合の処理の違い

例えば、先程のテーブルから「平均年齢」を計算したい場合を考えてみましょう。

「年齢」列のデータだけが欲しいのに、行指向の CSV では 一度全ての行を読み込まなければいけません。

そのため、不要なデータをスキャンすることになり、クエリ時間もコストも無駄にかかってしまいます。

  1. 一度全ての行を読み込む

     1,佐藤,18,男性,北海道
     2,鈴木,29,女性,大阪府
     3,高橋,50,女性,岡山県
     4,田中,90,男性,滋賀県
     5,伊藤,5,男性,三重県
    
  2. 年齢の列を抽出

     18,29,50,90,5
    
  3. 平均を計算

     (18 + 29 + 50 + 90 + 5) / 5 = 38.4
    

一方、列指向の Parquet では 「年齢」の列だけをピンポイントで読み込むことができます。

他の「ID」や「名前」などの列は読み込む必要がないため、スキャンするデータ量が大幅に削減され、クエリ時間もコストも効率的になります。

CSV の例で言うと、ステップ1の「全行読み込み」が不要になり、いきなりステップ2の「年齢列の抽出」から始められるイメージですね。

このように、列指向のデータ形式は 特定の列に対して集計やフィルタリングを行う場合 に特に効率的に処理を行うことができます。

Amazon Athena ではどうして列指向データ形式が適しているのか

Amazon Athena は、S3 上のデータに対して SQL クエリを実行できるサーバーレスの分析サービスです。

CSV や JSON などのテキスト形式のデータを扱うこともできますが、列指向のデータ形式である Parquet や ORC を使用することで、より効率的にクエリを実行することができるとされています。

それでは、Amazon Athena ではどうして列指向のデータ形式が適しているのでしょうか。

Amazon Athena の公式ドキュメント にはこのような記載があります。

列指向ストレージ形式には以下の特性があるため、Athena での使用に適しています。

  • 列のデータ型に合わせて選択された圧縮アルゴリズムによる列ごとの圧縮で、Amazon S3 のストレージ領域を節約し、ディスク容量とクエリの処理中における I/O を削減します。
  • Parquet および ORC での述語プッシュダウンにより、Athena クエリが必要なブロックのみを取得できるようになり、クエリパフォーマンスが向上します。Athena クエリがデータから特定の列値を取得すると、データブロック述語からの統計 (最大値や最小値など) を使用して、そのブロックを読み取るかスキップするかを判断します。
  • Parquet および ORC でのデータの分割により、Athena がデータの読み取りを複数のリーダーに分割して、クエリ処理時における並列化を向上させることが可能になります。

ふむふむ、なるほど。分かったような分からないような。。。
少し噛み砕いてみると次のようなことが言えそうです。

メリット1 : 圧縮して、データ量を小さくできる

  • 列指向だと、同じデータ型(数値や文字列など)の値が連続して並ぶため、データ圧縮がとても効きやすくなります
  • データが小さくなれば S3 から読み込むデータ量が減るのでクエリが速くなります
  • ついでに S3 のストレージコストと Amazon Athena のクエリ実行コストも削減できます

メリット2 : 不要なデータを丸ごと読み飛ばせる (述語プッシュダウン)

  • これが列指向の最大の強みです
  • Amazon Athena はクエリを実行する時、WHERE 句の条件(これを「述語」と呼びます)を使って、明らかに不要なデータブロックを丸ごと読み飛ばすことができます (これを「述語プッシュダウン」と呼びます)
  • 例えば、「年齢が30歳以上のユーザー」を取得するクエリを実行した場合、「年齢」列の値が30未満のデータブロックを丸ごと読み飛ばすことができるため、必要なデータのみを効率的に取得できます
    • ここについてはこの後の章でもう少し詳しく解説します

メリット3 : 並列処理でクエリを高速化できる

  • データを列ごとに保存しているため、Amazon Athena は内部で「君はこの列を読んで」「君はあの列を読んで」と複数のワーカーに手分けさせることができます
  • 並列で一気に読み込めるので、全体の処理時間が短縮されます

ちょっと深掘り : 高速化の秘密は、階層構造とファイル末尾の「目次」にある

先程は Parquet の保存イメージをテキストとして表現しましたが、実際には下図のような階層構造を持ったバイナリ形式で保存されています。

Parquet ファイル構造
 │
 ├─ 行グループ 1
 │   ├─ 列チャンク 'ID'
 │   ├─ 列チャンク '名前'
 │   └─ 列チャンク '年齢'
 │      ├─ ページ 1
 │      └─ ページ 2
 │
 ├─ 行グループ 2
 │   └─ ...
 │
 ├─ ...
 │
 └─ ファイルメタデータ
     └─ 各ブロックの統計情報や列チャンクの開始位置を記録

少し複雑に見えますが、各パーツの役割はシンプルです。

用語紹介

行グループ

  • 数百万行といった、ある程度まとまった行数のデータが格納される大きな塊
  • 巨大なテーブルデータを、扱いやすいサイズに水平分割しています

列チャンク

  • 1つの「行グループ」の中にある、1つの列のデータ
  • 例えば、「行グループ1」の中の「年齢」列のデータが集まっています

ページ

  • 「列チャンク」をさらに細かく分割したもので、実際にデータが圧縮・エンコードされる単位のこと
  • 例えば、「年齢」列のデータが圧縮されて保存される部分です
  • Parquet ファイルの末尾に記録されている 「目次」 のようなもの
  • ここには、各「行グループ」や「列チャンク」がファイルのどの位置から始まるか、といった情報に加えて、それぞれのデータブロックの統計情報(例えば、年齢列の最小値・最大値、null の数など)が記録されています

Amazon Athena ではクエリが来ると、まず巨大なファイル全体を読むのではなく、末尾の小さな「ファイルメタデータ」だけを読み込みます

例えば WHERE age >= 30 というクエリが来た場合、Amazon Athena はメタデータに書かれた統計情報をチェックし、「行グループ1の年齢列の最大値は29歳」 という情報を発見します。

その瞬間、「この行グループには30歳以上の人は一人もいない」 と判断し、「行グループ1」の巨大なデータブロックを丸ごと読み飛ばします

これが、先ほど「メリット2」で紹介した「述語プッシュダウン」の強力さの秘密です。

Parquet の階層構造と、メタデータ(統計情報)のおかげで、無駄なデータ読み込みを大幅に減らすことができるのです。

参考 : File Format | Parquet

Amazon Athena で実際に CSV と Parquet をクエリ比較してみる

列指向データ形式と Amazon Athena でのメリットについて理解できたところで、実際に Parquet のデータを使うと どれほどクエリ効率に差が出るのか が気になりますよね。

AWS の公式ブログ『Amazon Athena のパフォーマンスチューニング Tips トップ 10』では、Parquet のような列指向フォーマットを利用することがパフォーマンス向上のための重要な Tips になると紹介されています。

さらに、「5. 列指向のファイル形式の利用」 にて、テキスト形式 (CSV) と Parquet のクエリを比較した結果が掲載されているので、ここではその内容を引用します。

クエリ SELECT l_orderkey
FROM lineitem
WHERE l_partkey = 17766770
テキスト形式と比較した節約分
テキスト gzip データ 実行時間 : 11.9 秒
スキャンしたデータ : 23.7 GB
コスト : $0.1
Parquet gzip データ 実行時間 : 2.1 秒 ~ 82% 高速化
スキャンしたデータ : 2.0 GB ~ 91% 削減
コスト : $0.009 ~ 91% 安価

データを Parquet 形式にすることで、テキストデータと比べて 「実行時間・スキャンデータ量・実行コスト」の全てにおいて大幅な改善 が見られます。

このように、列指向のデータ形式を利用することで、Amazon Athena のクエリパフォーマンスを大幅に向上させることができるのです。

特に、上記クエリのように 「特定の列のみを SELECT (l_orderkey)」 し、かつ 「特定の列を WHERE 句でフィルタリング (l_partkey)」 するような分析クエリでは、Parquet のメリットが最大限に活かされます。

まとめ

この記事の執筆を通じて、Parquet のメリットや Amazon Athena での活用方法について理解を深めることができました。

Parquet の真の強みは、列指向のデータ形式によって 不要なデータを読み飛ばせる ことにあります。

  • Parquet はデータを列ごとに保存する 「列指向」 フォーマット
  • Amazon Athena では、列指向にすることで 「圧縮が効く」「不要な列を読まない」「並列処理しやすい」 というメリットがある
  • その結果、クエリが速くなり、スキャンデータ量が減ることで安くなる
  • AWS 公式の比較でも、実行時間・コスト共に 90%近い改善 が見られるケースもある

列指向データの使用以外にも、「パーティショニング」や「圧縮」、「ファイルサイズの最適化」など、Amazon Athena のパフォーマンスを向上させるための Tips はたくさんあります。

その辺りもぜひ「Amazon Athena のパフォーマンスチューニング Tips トップ 10」を参考にチューニングしてみてください。

最後までお読みいただき、ありがとうございました。

香取 拓哉 (記事一覧)

2023年度新卒入社

アプリケーションサービス部ディベロップメントサービス3課所属