- バッチロード・ストリーミング・BigQuery Data Transfer Service・外部データソースという 4 つの取り込み方法の使い分けを理解する
bq loadコマンドとLOAD DATA文で CSV / JSON / Avro / Parquet をロードし、書き込みモードを使い分ける- スキーマ自動検出の仕組みと限界を理解し、明示スキーマを使うべき場面を判断する
- ローカルファイルと Cloud Storage からのロードの違いを理解し、それぞれの制約を踏まえて手順を選ぶ
bq extractとEXPORT DATA文でテーブルを Cloud Storage へ書き出し、ロードとエクスポートの往復を体験する
前提: ハンズオン 3-1〜3-3 はサンドボックスで完走可(無料枠内)。ハンズオン 3-4(エクスポート)のみ Cloud Storage バケットの作成が必要なため課金プロジェクト必須(概算 1 円未満)。
取り込み方法の全体地図
BigQuery へデータを入れる方法は 1 つではありません。データの発生源・鮮度要件・運用したい人手のかけ方によって、選ぶべき経路が変わります。公式ドキュメントは取り込み方法を大きく「バッチロード」「ストリーミング」「BigQuery Data Transfer Service による定期転送」「外部データソースへのフェデレーション」に整理しています。
| 方法 | 主な用途 | この章での扱い |
|---|---|---|
| バッチロード | 大量データを定期的・一括で取り込む | この章の主役。bq load と LOAD DATA 文 |
| ストリーミング | メッセージングシステムから秒〜分単位で近リアルタイム取り込み | 第 12 章で詳説。この章では扱わない |
| BigQuery Data Transfer Service | Google 広告・YouTube・SaaS 等からのスケジュール実行の自動化 | 位置づけのみ。サンドボックス非対応 |
| 外部データソース・フェデレーション | ロードせずに外部の場所へ直接クエリする | 第 10 章で詳説 |
ロードジョブの費用・ロケーション・フォーマット
バッチロードの実体は「ロードジョブ」です。公式ドキュメントには「共有スロットプール(shared slot pool)を使う限り、BigQuery へのバッチロードに料金は発生しない」と明記されています(2026-08 時点)。ロード自体は無料ですが、ロード先データセットのロケーションとロード元(Cloud Storage バケット等)のロケーションが一致している必要があり(第 2 章)、ロケーションをまたぐ場合はデータ転送料金が発生することがあります。
ロード可能な形式は Avro・CSV・JSON(改行区切り)・ORC・Parquet です。形式によって並列読み込みの可否が変わり、ロード時間に直結します。
| 形式 | 並列読み込み | 特徴 |
|---|---|---|
| CSV / JSON | 非圧縮なら可、圧縮(.gz)は不可 | 人間が読みやすく自動検出も効くが、圧縮するとロードが遅くなる |
| Avro | 圧縮していても可 | 自己記述型でスキーマ不要。ロードが最速の部類 |
| Parquet | 可(列指向) | 列単位の効率的なエンコーディング。分析ワークロードの定番 |
| ORC | 可(ストライプ単位) | ロード時間の最適化には 1 ストライプ約 256 MB 以下が目安 |
ローカルファイルと Cloud Storage、どちらからロードするか
バッチロードのソースには、ローカルマシンと Cloud Storage の両方を指定できますが、性質はかなり異なります。
- ローカルファイル: コンソール・
bq load・API・クライアントライブラリのいずれからでもロードできます。ただしコンソールからのアップロードは 1 ファイル 100 MB までで、ワイルドカードやカンマ区切りの複数ファイル指定はローカルでは使えません(1 ファイルずつロードします)。BigQuery サンドボックスの制限一覧(ストリーミング・DML・BigQuery Data Transfer Service が非対応)にローカルファイルロードは含まれていないため、この方法はサンドボックスでも利用できます。 - Cloud Storage:
bq loadとLOAD DATA文の両方が対応します。ただし Cloud Storage 自体は BigQuery サンドボックスの無料枠の対象外で、バケットを新規作成するには課金が有効なプロジェクトが必要です。すでにある公開バケットから読み取るだけなら、自分でバケットを作る必要はなく課金プロジェクトも不要です。
スキーマ自動検出と明示スキーマ
CSV と JSON はスキーマを自己記述しないため、BigQuery はスキーマ自動検出(--autodetect)を提供しています。仕組みはシンプルで、データソースからランダムに 1 ファイルを選び、先頭から最大 500 行をサンプルとして型を推定します。CSV では区切り文字とヘッダー行の有無も推定し、JSON ではネストしたオブジェクトを RECORD 型、配列を繰り返しフィールドとして扱います。
ただし限界もあります。公式ドキュメントには次のような注意点が明記されています。
- 列がすべて空の場合、自動検出は
STRING型にフォールバックする - 「1 行目が文字列のみで、他の行に文字列以外の型がある場合にヘッダー行と判定する」という仕組みのため、全列が STRING 型の CSV ではヘッダー行を正しく除外できないことがある
2025-06-16T16:55:22Zのような一部のタイムスタンプ表記は、自動検出を有効にしないと認識されない- Avro・Parquet・ORC は自己記述型なので自動検出は不要
スキーマの精密な制御が必要な場面、非標準の日時形式を扱う場面、そして全列 STRING 型の CSV を扱う場面では、明示スキーマを使うべきです。
書き込みモードとパーティションへのロード
ロードジョブには 3 つの書き込みモードがあります。
- WRITE_EMPTY: テーブルが空の場合のみ書き込む。既存データがあるとエラーになる
- WRITE_APPEND(既定): テーブルの末尾に追記する
- WRITE_TRUNCATE: 既存データをすべて消してから書き込む
LOAD DATA 文ではこれを INTO(追記。テーブルが無ければ新規作成)と OVERWRITE(置換)というキーワードで表現します。パーティション表に対しては、PARTITION BY 句を付けて新規作成時にパーティション定義を与えるほか、PARTITIONS (partition_column_name=partition_value) 句を使うと特定の 1 パーティションだけを追記・置換できます(このときは LOAD DATA INTO で始める必要があります)。
転送サービスとエクスポート — 逆方向のデータ移動
BigQuery Data Transfer Service は、Google 広告・YouTube・Cloud Storage・Amazon S3・Salesforce といった多様なソースから BigQuery へのデータ移動を、スケジュールに基づいて自動化するサービスです。サービス自体に料金はかからず、転送後のデータに対する通常のストレージ・クエリ課金だけが発生します。ただし BigQuery サンドボックスでは利用できないため、本書ではこの位置づけの説明にとどめ、実際の設定はコンソールの「Pipelines & Connections」から行うという流れだけ押さえておきます。
逆方向、つまりテーブルから Cloud Storage への書き出しには bq extract コマンドと EXPORT DATA 文を使います(具体的なコマンドはハンズオン 3-4 で実行します)。CSV・JSON・Avro・Parquet 形式に対応し、1 ファイルにつき論理データサイズ 1 GB までという制限があるため、超える場合はワイルドカードで複数ファイルに分割します。EXPORT DATA 文なら SQL の中で完結させられます。
EXPORT DATA
OPTIONS (
uri = 'gs://PROJECT_ID-handson-ch03/us_states/*.csv',
format = 'CSV',
overwrite = true,
header = true)
AS (
SELECT state_name, state_abbr
FROM handson_ch03.us_states
);
| 制限項目 | 値(2026-08 時点) |
|---|---|
| 1 ファイルの論理データサイズ上限 | 1 GB(超える場合はワイルドカードで分割) |
| 1 エクスポートジョブあたりのワイルドカード URI | 最大 500 |
| 1 プロジェクトあたりのエクスポートジョブ数 | 1 日 100,000 件 |
公開データセット cloud-samples-data の米国州名 CSV をローカルに保存し、自動検出でロードします。ファイルは約 700 バイトなのでサンドボックスで無料・数秒で完走します。
- US ロケーションでデータセットを作成し、米国州名 CSV をローカルにダウンロードします(
name,post_abbrの 2 列 STRING、ヘッダー 1 行 + データ 50 行)。
bq mk --dataset --location=US PROJECT_ID:handson_ch03
curl -o us-states.csv \
https://storage.googleapis.com/cloud-samples-data/bigquery/us-states/us-states.csv
- 自動検出でロードします。
bq load \
--autodetect \
--source_format=CSV \
--location=US \
handson_ch03.us_states \
./us-states.csv
- 行数を確認します。
SELECT COUNT(*) AS row_count FROM `PROJECT_ID.handson_ch03.us_states`;
期待される出力は row_count = 50 です。ただし自動検出の仕組み上、この CSV のように 2 列とも STRING 型の場合はヘッダー行がデータ扱いされ 51 になることがあります(次のハンズオンで明示スキーマによる確実な方法を試します)。
後片付け: このテーブルは次のハンズオンで作り直すため、いったんそのままで構いません。
同じ CSV を、今度は Cloud Storage の公開バケットから直接、明示スキーマで確実にロードします。公開データを読むだけなので追加の課金プロジェクトは不要です(処理量は 1 KB 未満)。
- まずテーブルを作り直し、明示スキーマと
skip_leading_rowsでヘッダーを確実に除外します。
LOAD DATA OVERWRITE handson_ch03.us_states
(state_name STRING, state_abbr STRING)
FROM FILES (
format = 'CSV',
skip_leading_rows = 1,
uris = ['gs://cloud-samples-data/bigquery/us-states/us-states.csv']
);
SELECT COUNT(*)で50になっていることを確認します。- 既定の書き込みモード(追記)を確認するため、先頭の
LOAD DATA OVERWRITEをLOAD DATA INTOに変えるだけで同じ文をもう一度実行します。
行数は 100 になります(重複を許して追記された状態)。OVERWRITE で再実行すれば 50 に戻ります。
後片付け: このテーブルはハンズオン 3-4 で使うため、最後に OVERWRITE を実行して 50 行の状態に戻しておきます。
公開データセットの取引サンプル(6 行、1 KB 未満)を、LOAD DATA 文 1 本でパーティション表として新規作成しながらロードします。サンドボックスで無料・数秒で完走します。
- パーティション定義付きでロードします。
LOAD DATA INTO handson_ch03.transactions
(timestamp TIMESTAMP, origin STRING, destination STRING, transaction_amount NUMERIC)
PARTITION BY TIMESTAMP_TRUNC(timestamp, DAY)
FROM FILES (
format = 'CSV',
skip_leading_rows = 1,
uris = ['gs://cloud-samples-data/bigquery/sample-transactions/transactions.csv']
);
- 作られたパーティションを確認します。
SELECT partition_id, total_rows
FROM `PROJECT_ID.handson_ch03.INFORMATION_SCHEMA.PARTITIONS`
WHERE table_name = 'transactions'
ORDER BY partition_id;
6 行のデータ(2017-03-18 は同日 2 件)が 5 つの異なる日付にまたがっているため、パーティションは 5 個作成されます。
後片付け:
bq rm -f -t PROJECT_ID:handson_ch03.transactions
ハンズオン 3-2 で作った 50 行のテーブルを、自分の Cloud Storage バケットへ書き出します。バケットの新規作成には課金が有効なプロジェクトが必要です。50 行・1 KB 未満のデータなので Cloud Storage の保存料金は月あたり実質ゼロに近い金額(US マルチリージョン Standard storage は 1 GB あたり月額 0.026 米ドル、2026-08 時点)です。
- データセットと同じ US ロケーションにバケットを作成します。
gcloud storage buckets create gs://PROJECT_ID-handson-ch03 --location=US
- エクスポートします。
bq extract \
--destination_format=CSV \
handson_ch03.us_states \
gs://PROJECT_ID-handson-ch03/us_states/*.csv
- 書き出されたファイルを確認します。
gcloud storage ls gs://PROJECT_ID-handson-ch03/us_states/
1 ファイルに収まるサイズなら us_states/000000000000.csv のような 1 ファイルが、複数に分割された場合は連番のファイルが確認できます。
後片付け:
gcloud storage rm -r gs://PROJECT_ID-handson-ch03
bq rm -r -f -d PROJECT_ID:handson_ch03
つまずきポイント
skip_leading_rows に切り替えます。
LOAD DATA 文の FROM FILES の uris は gs://・s3://・azure:// といったクラウド URI のみを受け付け、ローカルファイルパスは指定できません(なお s3:// / azure:// は BigQuery Omni の接続を WITH CONNECTION で指定する前提です)。ローカルファイルをロードしたい場合は bq load コマンドを使います。
bq load には --location を明示し、バケット作成時のロケーションと揃えます。
理解度チェック
Q1. バッチロードとストリーミングは、それぞれどんな場合に選ぶべきか?
データを定期的・一括で取り込んでよく、秒〜分単位の鮮度が不要ならバッチロードを選びます。メッセージングシステムから近リアルタイムで反映したい場合はストリーミング(第 12 章の Storage Write API 等)を選びます。
Q2. ロード時に Avro や Parquet が推奨されるのはなぜか?
どちらも自己記述型でスキーマ推定が不要なうえ、圧縮していても複数ワーカーで並列に読み込めるためです。CSV / JSON は圧縮すると単一ストリームでの逐次読み込みになり、ロードが遅くなります。
Q3. スキーマ自動検出が失敗しやすいのはどんなケースか?
全列が空でデフォルトが STRING 型に倒れるケース、全列が STRING 型でヘッダー行を判定できないケース、そして一部の非標準なタイムスタンプ表記が認識されないケースです。これらの場面では明示スキーマを使います。
Q4.(シナリオ)全列が STRING 型の日次 CSV ファイルを、毎日既存テーブルへ追記していきたい。最も適切な方法は?
A. bq load --autodetect のみを毎日実行する B. 明示スキーマ + skip_leading_rows=1 を指定し、既定の書き込みモード(追記)で bq load する C. 毎回 LOAD DATA OVERWRITE で全置換する D. Cloud Storage を使わずローカルファイルだけで運用し続ける
B。全列 STRING の CSV は自動検出でヘッダーを誤認識する恐れがあるため A は不適切です。C は「追記していきたい」という要件に反し、過去データを毎回消してしまいます。D はロード自体は可能でも、ローカルロードはワイルドカードが使えず 1 ファイルずつの逐次処理になるため、日次の継続運用には Cloud Storage 経由が向いています。
Q5.(シナリオ)ローカル PC に 50 MB の CSV があり、Cloud Storage バケットを作る予算はまだ承認されていない。BigQuery サンドボックスへロードするには?
A. LOAD DATA 文でローカルパスを直接指定する B. まず Cloud Storage バケットを作ってからロードする C. bq load コマンドでローカルファイルを直接指定してロードする D. サンドボックスではロードそのものができないので諦める
C。LOAD DATA 文はローカルパスを受け付けないため A は誤りです。B は課金プロジェクトが前提になり要件に反します。ローカルファイルのロードはサンドボックスの非対応機能一覧に含まれないため D も誤りです。
まとめと次章へ
- 取り込み方法はバッチロード・ストリーミング・BigQuery Data Transfer Service・外部データソースの 4 種類に整理でき、この章はバッチロードとエクスポートが主役だった
- ロードジョブ自体は共有スロットプールを使う限り無料。フォーマットは並列読み込み可能な Avro / Parquet が有利
- スキーマ自動検出は 500 行サンプリングで動くが、全列 STRING の CSV ではヘッダー判定に失敗することがある。明示スキーマがその保険になる
- 書き込みモードは WRITE_EMPTY / WRITE_APPEND(既定)/ WRITE_TRUNCATE の 3 種類。
LOAD DATA文ではINTO/OVERWRITEに対応する - ローカルファイルはコンソール・
bq loadなどからロード可能(コンソールは 100 MB まで・ワイルドカード不可)。Cloud Storage はbq loadとLOAD DATAの両方に対応するが、自分のバケットを使う操作(エクスポート含む)には課金プロジェクトが必要
データが正しく入ったので、次章からはいよいよ GoogleSQL でそのデータに問い合わせていきます。