BigQuery で Parquet と CSV を比較してみる

BigQuery で Parquet と CSV を比較してみる

Clock Icon2025.01.30

Google Cloud データエンジニアのはんざわです。

皆さんは Parquet を使っていますか?
Parquet は、大規模データ処理に最適な列指向のファイル形式です。

今回のブログでは、列指向の Parquet と行指向の CSV を BigQuery で扱った場合のパフォーマンスなどの違いを検証し、比較してみたいと思います。

Apache Parquet とは?

Apache Parquet は、大規模なデータ処理に最適化されたオープンソースの列指向のデータファイル形式です。従来の MySQL や PostgreSQL、CSV などは行指向のデータストレージ構造に分類されるのに対し、Parquet は列指向に分類されます。

列指向のデータ形式では、列単位でデータを圧縮・エンコーディングして格納します。行指向のデータ形式と比較すると、自然と列内には同様のデータが含まれる可能性が高くなるため、圧縮効率が向上します。

また、一部のカラムを利用した分析の場合、不要なカラムのデータの読み込みを省略できるため、高速なクエリ処理が可能です。

Parquet の内部のデータフォーマットについて詳しく知りたい方は、以下のブログをおすすめします。

https://note.com/ruzgar08/n/nd25adcf80705

やりたいこと

今回のブログでは、以下の項目を測定し、データファイル形式や圧縮形式による違いを比較します。

BQ クエリ実行時間 BQ 平均スロット使用量 GCS ストレージ容量
Parquet(非圧縮)
Parquet(gzip)
Parquet(Snappy)
CSV

この表の通り、以下の3つの軸から検証を行います。

  1. データファイル形式(Parquet と CSV)の違い

    • Parquet と CSV で、BigQuery のパフォーマンスにどのような差が生じるのかを確認します。
  2. 圧縮形式の違い

    • Parquet の非圧縮ファイルと圧縮ファイル(gzip と Snappy)におけるパフォーマンスの違いを測定します。

参考:圧縮データと非圧縮データを読み込む

  1. 測定項目
    • 測定するのは、以下の3つの指標です。クエリ実行には LOAD DATA 構文を使用し、Cloud Storage バケットからそれぞれのファイルを参照します。
      • BQ クエリ実行時間:BigQuery のクエリ実行時間
      • BQ 平均スロット使用量:BigQuery のクエリ実行時に消費される平均のスロット量
      • GCS ストレージ容量:Cloud Storage にデータを保存する際のストレージ容量

事前準備

まずは、検証を行うために、各ファイル形式のサンプルデータを 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

平均スロット使用量の計算方法については、以下の公式ブログを参考にしています。

https://cloud.google.com/blog/ja/topics/developers-practitioners/monitoring-bigquery-reservations-and-slot-utilization-information_schema/

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 のエンコーディング方法について知りたい方は、以下のブログをおすすめします。

https://ishitonton.hatenablog.com/entry/2020/09/18/000035

gzip は Snappy よりも圧縮率が高いことがわかりますが、その分処理時間が長くなる傾向があります。一方、Snappy は高速な圧縮・解凍を目的として設計されているため、処理時間が短くなる特徴があります。
これらはトレードオフの関係にあるため、要件に合わせて適切な圧縮形式を選択しましょう。

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.