BigQuery で Parquet と CSV を比較してみる
Google Cloud データエンジニアのはんざわです。
皆さんは Parquet を使っていますか?
Parquet は、大規模データ処理に最適な列指向のファイル形式です。
今回のブログでは、列指向の Parquet と行指向の CSV を BigQuery で扱った場合のパフォーマンスなどの違いを検証し、比較してみたいと思います。
Apache Parquet とは?
Apache Parquet は、大規模なデータ処理に最適化されたオープンソースの列指向のデータファイル形式です。従来の MySQL や PostgreSQL、CSV などは行指向のデータストレージ構造に分類されるのに対し、Parquet は列指向に分類されます。
列指向のデータ形式では、列単位でデータを圧縮・エンコーディングして格納します。行指向のデータ形式と比較すると、自然と列内には同様のデータが含まれる可能性が高くなるため、圧縮効率が向上します。
また、一部のカラムを利用した分析の場合、不要なカラムのデータの読み込みを省略できるため、高速なクエリ処理が可能です。
Parquet の内部のデータフォーマットについて詳しく知りたい方は、以下のブログをおすすめします。
やりたいこと
今回のブログでは、以下の項目を測定し、データファイル形式や圧縮形式による違いを比較します。
BQ クエリ実行時間 | BQ 平均スロット使用量 | GCS ストレージ容量 | |
---|---|---|---|
Parquet(非圧縮) | |||
Parquet(gzip) | |||
Parquet(Snappy) | |||
CSV |
この表の通り、以下の3つの軸から検証を行います。
-
データファイル形式(Parquet と CSV)の違い
- Parquet と CSV で、BigQuery のパフォーマンスにどのような差が生じるのかを確認します。
-
圧縮形式の違い
- Parquet の非圧縮ファイルと圧縮ファイル(gzip と Snappy)におけるパフォーマンスの違いを測定します。
- 測定項目
- 測定するのは、以下の3つの指標です。クエリ実行には
LOAD DATA
構文を使用し、Cloud Storage バケットからそれぞれのファイルを参照します。- BQ クエリ実行時間:BigQuery のクエリ実行時間
- BQ 平均スロット使用量:BigQuery のクエリ実行時に消費される平均のスロット量
- GCS ストレージ容量:Cloud Storage にデータを保存する際のストレージ容量
- 測定するのは、以下の3つの指標です。クエリ実行には
事前準備
まずは、検証を行うために、各ファイル形式のサンプルデータを Cloud Storage にエクスポートします。サンプルデータの準備の過程は省略します。
サンプルデータの概要とフォルダのパスは以下の通りです。
-
サンプルデータ
-
bigquery-public-data.github_repos.files
- 行数:
2309424945
- 合計論理バイト数:
321.37 GB
- 行数:
-
-
Cloud Storage
-
gs://cm-hanzawa-parquet/
parquet/*.parquet
parquet-gzip/*.parquet.gz
parquet-snappy/*.snappy.parquet
csv/*.csv
-
全てのフォルダに 346 件ずつファイルが配置されています。
-
検証
以下のクエリで、読み込み先のテーブルを作成します。
テーブル定義は、サンプルデータのスキーマ構造に合わせています。
CREATE OR REPLACE TABLE parquet_csv.target (
repo_name STRING,
ref STRING,
path STRING,
mode INT64,
id STRING,
symlink_target STRING
);
1. BQ クエリ実行時間と平均スロット使用量
ここからは、LOAD DATA
構文を複数回実行し、クエリ実行時間と平均スロット使用量を測定します。
測定には、INFORMATION_SCHEMA.JOBS_BY_PROJECT
を利用し、ジョブごとの実行時間と平均スロット使用量を取得しています。
SELECT
-- クエリ実行時間
TIMESTAMP_DIFF(end_time, start_time, SECOND) AS time_diff,
-- 平均スロット使用量
ROUND(total_slot_ms / TIMESTAMP_DIFF(end_time,start_time,MILLISECOND), 2) AS avg_slots
FROM
`region-us-central1`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE
statement_type = 'LOAD_DATA'
ORDER BY
start_time DESC
平均スロット使用量の計算方法については、以下の公式ブログを参考にしています。
1. Parquet(非圧縮)
LOAD DATA INTO parquet_csv.target
FROM FILES (
format = 'PARQUET',
uris = ['gs://cm-hanzawa-parquet/parquet/*.parquet']
);
-- クエリ実行時間, 平均スロット使用量
-- 1回目:49秒, 1074.54
-- 2回目:49秒, 1087.93
-- 3回目:46秒, 1155.34
-- 平均値:47秒, 1105.94
2. Parquet(gzip)
LOAD DATA INTO parquet_csv.target
FROM FILES (
format = 'PARQUET',
uris = ['gs://cm-hanzawa-parquet/parquet-gzip/*.parquet.gz']
);
-- クエリ実行時間, 平均スロット使用量
-- 1回目:1分36秒, 676.06
-- 2回目:1分29秒, 804.97
-- 3回目:1分00秒, 1103.28
-- 平均値:1分22秒, 861.44
3. Parquet(Snappy)
LOAD DATA INTO parquet_csv.target
FROM FILES (
format = 'PARQUET',
uris = ['gs://cm-hanzawa-parquet/parquet-snappy/*.snappy.parquet']
);
-- クエリ実行時間, 平均スロット使用量
-- 1回目:58秒, 938.65
-- 2回目:51秒, 975.03
-- 3回目:52秒, 1035.24
-- 平均値:54秒, 982.97
4. CSV
LOAD DATA INTO parquet_csv.target
FROM FILES (
format = 'CSV',
allow_quoted_newlines = True,
preserve_ascii_control_characters = True,
uris = ['gs://cm-hanzawa-parquet/csv/*.csv']
);
-- クエリ実行時間, 平均スロット使用量
-- 1回目:2分57秒, 729.0
-- 2回目:2分48秒, 686.31
-- 3回目:2分38秒, 705.57
-- 平均値:2分48秒, 706.96
2. GCS ストレージ容量
次に、gcloud storage du
のコマンドを使用し、Cloud Storage の各フォルダごとのストレージ容量を算出しています。
コマンドやオプションの詳細は、以下のドキュメントを参考にしてください。
1. Parquet(非圧縮)
gcloud storage du -s -r gs://cm-hanzawa-parquet/parquet/
220.49GiB gs://cm-hanzawa-parquet/parquet/
2. Parquet(gzip)
gcloud storage du -s -r gs://cm-hanzawa-parquet/parquet-gzip/
75.57GiB gs://cm-hanzawa-parquet/parquet-gzip/
3. Parquet(Snappy)
gcloud storage du -s -r gs://cm-hanzawa-parquet/parquet-snappy/
125.66GiB gs://cm-hanzawa-parquet/parquet-snappy/
4. CSV
gcloud storage du -s -r gs://cm-hanzawa-parquet/csv/
310.62GiB gs://cm-hanzawa-parquet/csv/
検証結果のまとめと考察
これらの結果をまとめると以下のような表になります。
BQ クエリ実行時間(秒) | BQ 平均スロット使用量 | GCS ストレージ容量(GiB) | |
---|---|---|---|
Parquet(非圧縮) | 47 | 1105.94 | 220.49 |
Parquet(gzip) | 82 | 861.44 | 75.57 |
Parquet(Snappy) | 54 | 982.97 | 125.66 |
CSV | 168 | 706.96 | 310.62 |
BQ クエリ実行時間の考察
- 全体的に Parquet は CSV よりも読み込み速度が速い
- 非圧縮形式は圧縮形式よりも読み込み速度が速い
- Parquet の圧縮形式では、Snappy の方が gzip よりも読み込み速度が速い
Parquet が CSV よりも読み込みが速かった要因として、Parquet の方がデータ容量が小さいため、ストレージからの読み込み量が減り、I/O のボトルネックが軽減されたと考えられます。
BQ 平均スロット使用量の考察
- 全体的に実行時間が短いほどスロット使用量が多い傾向がある
一般的に、圧縮ファイルは解凍処理が必要なため、CPU リソースを多く消費します。しかし、今回の検証では、非圧縮形式の方がスロット使用量が多い結果となりました。
これは、非圧縮形式では解凍処理が不要な分、BigQuery がより多くのスロットを同時に使用し、並列処理で高速化しようとしたためではないかと考えられます。
GCS ストレージ容量の考察
- Parquet は非圧縮でも元のデータ量よりもファイルサイズが小さい
- Parquet の圧縮形式では、Snappy よりも gzip の方がファイルサイズが小さい
Parquet は非圧縮形式でもデータを圧縮・エンコーディングして格納するため、非圧縮の CSV ファイルと比較してもファイルサイズが小さいことがわかります。
Parquet のエンコーディング方法について知りたい方は、以下のブログをおすすめします。
gzip は Snappy よりも圧縮率が高いことがわかりますが、その分処理時間が長くなる傾向があります。一方、Snappy は高速な圧縮・解凍を目的として設計されているため、処理時間が短くなる特徴があります。
これらはトレードオフの関係にあるため、要件に合わせて適切な圧縮形式を選択しましょう。