インフラ

BigQuery APIの選び方:REST・クライアントライブラリ・Storage APIの使い分けと権限・リトライ設計

BigQuery APIという名前で呼ばれているものは、実際には1つのAPIではありません。ジョブとメタデータを操作するREST v2、テーブルの行を並列に取り出すStorage Read API、高スループットで書き込むStorage Write API、そして共有や予約を扱う管理系のAPI群に分かれていて、それぞれ認証の付け方も課金の仕方も上限値も違います。この記事は、自社のアプリケーションや業務システムからBigQueryをプログラムで叩く実装者に向けて、どの面をどの条件で選ぶか、サービスアカウントにどのロールを積むか、毎秒100リクエストという上限をどう再試行の設計に落とすかを、2026年8月17日時点のGoogle Cloud公式ドキュメントの実測から整理したものです。人の手でコンソールやbqコマンドを触る手順はBigQueryの使い方をまとめた解説に譲ります。

まとめ:叩く面を先に決めれば、権限も再試行も自然に決まる

先に置く結論は次のとおりです。読み書きするデータ量が小さく、SQLを投げて結果を受け取るだけなら、REST v2のジョブAPIをクライアントライブラリ越しに使えば足ります。1回の処理で数百万行を取り出す、あるいは毎秒数万行を書き込むという段になって初めて、Storage Read APIとStorage Write APIへ降りる価値が出ます。この境界を先に決めないまま実装を始めると、途中でクライアントの種類ごと差し替えることになる。

権限も面ごとに分かれています。ジョブを起動する権限、テーブルのデータへ到達する権限、読み取りセッションを張る権限は別のロールです。3つを混ぜて bigquery.admin を1枚配ると当座は動きますが、後から絞り込む作業が必ず発生します。

再試行の設計で押さえる数字は2つ。大半のコアメソッドは1ユーザー1メソッドあたり毎秒100リクエスト、jobs.get だけが毎秒1,000リクエストです。この差があるため、ジョブの投入は絞り、完了確認は多めに回すという非対称な設計が理屈に合います。あわせて、ジョブIDを自分で決めておけば、再送しても同じジョブが二重に走ることはありません。

BigQuery APIは4系統に分かれておりどれを叩くかを先に決める

公式のAPIリファレンスは、BigQueryを操作する面を用途ごとに分けています。名前が似ているせいで最初は区別しにくいのですが、担当範囲は明確に切れている。

BigQuery API本体はジョブとメタデータの操作を担うREST v2

REST v2が提供する資源は、datasets、jobs、tables、tabledata、models、routines、projects、rowAccessPolicies です。データセットを作る、テーブルのスキーマを読む、クエリジョブを投げる、読み込みジョブを起こす、といった操作はすべてここに集まっています。エンドポイントはHTTPとJSONで、認証はOAuth 2.0のアクセストークンをヘッダに載せる形です。

POST https://bigquery.googleapis.com/bigquery/v2/projects/PROJECT_ID/jobs
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

結果の受け取りには tabledata.list や jobs.getQueryResults を使いますが、この経路はページネーションで1ページずつ返す作りです。数万行までなら問題なく、数百万行を超えると往復回数がそのまま所要時間になります。

Storage Read APIは行の取り出しを並列化する読み取り専用面

Storage Read APIは、テーブルの中身を読み出すことに特化した別の面です。CreateReadSession を呼ぶと、テーブルの内容が1つ以上のストリームに分割され、それぞれを並列に読めるようになります。列の部分投影、行のフィルタ、スナップショット時刻の指定も同じセッションの設定で渡せる。

この面はREST v2とは別に課金されます。1TiBあたり1.10ドルで、請求先アカウントごとに毎月300TiBまでは無料です。読み取り量が無料枠に収まる規模なら、実質的な追加費用なしで往復回数を減らせます。課金体系全体の分解はBigQueryの料金の内訳と監視方法をまとめた解説で扱いました。

Storage Write APIはgRPC版とREST版で単価が2倍以上違う

書き込み側の専用面がStorage Write APIです。ストリームは4種類あります。既定ストリームは作成せずに使えて、書いた行はすぐクエリで見える代わりに配信保証は最低1回。pending型はコミットするまでバッファへ溜め、まとめて原子的に反映するのでバッチ処理向き。committed型は即時可視でありながら、オフセットを指定すると厳密1回の配信になります。buffered型は行単位でコミットする高度な型で、実質的にApache Beam向けの選択肢です。

gRPC版とREST版で価格が違う点は見落としやすい。gRPC版は1GiBあたり0.025ドルで毎月2TiBまで無料、REST版のストリーミングinsertは200MiBあたり0.01ドル、つまり1GiBあたり0.05ドルです。gRPC版が半額で、しかも厳密1回の配信が使える。公式も新規プロジェクトにはgRPC版を推奨すると明記しています。

共有と予約と転送はそれぞれ別サービスのAPIに切り出されている

残りは管理系です。スロットの購入と割り当てを扱うReservation API、定期取り込みを設定するData Transfer Service API、組織をまたいでデータセットを配るBigQuery Sharing(旧Analytics Hub)のAPI、列単位・行単位のアクセス制御を定義するData Policy API、他DWHからのSQL変換を担うMigration Service、外部データソースへの接続を保持するConnection APIがあります。

BigQuery Sharingは、データを複製せずに公開側のテーブルを参照させる仕組みで、購読すると自分のプロジェクトにリンクデータセットが作られます。社外へデータを配る要件が出たとき、テーブルをコピーして配る自前実装を書く前に、この面が使えないかを先に確かめてください。定期取り込みのほうはData Transfer Serviceの対応ソースとスケジュール設計の解説に整理してあります。

RESTを直接叩くかクライアントライブラリに寄せるかの判断軸

REST v2はHTTPで叩けるので、curlでも自作のHTTPクライアントでも動きます。それでも実務の大半はクライアントライブラリに寄せたほうが安く済む。理由は機能の差ではなく、周辺処理を誰が書くかの差です。

クライアントライブラリは7言語で提供され認証とリトライを内包する

公式のクライアントライブラリはC#、Go、Java、Node.js、PHP、Python、Rubyの7言語です。導入は各言語のパッケージマネージャで完結します。

pip install --upgrade google-cloud-bigquery
npm install @google-cloud/bigquery
composer require google/cloud-bigquery
gem install google-cloud-bigquery

ライブラリが肩代わりするのは3つです。1つ目は認証で、Application Default Credentials(ADC)が定義済みの場所から資格情報を探すため、コードに鍵のパスを書かずに済みます。2つ目はジョブ完了のポーリングで、投げたクエリが終わるまでの待機を内部で回してくれる。3つ目は再試行で、一時的なエラーに対する指数バックオフが既定で組み込まれています。

from google.cloud import bigquery

client = bigquery.Client()
rows = client.query("SELECT order_date, SUM(amount) FROM ds.sales GROUP BY 1").result()

RESTを直接叩く価値が残るのは対応言語外と依存を減らす場面

直接叩く判断が妥当なのは2つの場合に絞られます。1つは、7言語に含まれない処理系から呼ぶとき。もう1つは、実行環境に持ち込む依存関係を極限まで減らしたいときで、コンテナのサイズやサプライチェーンの監査範囲が理由になります。

この道を選ぶなら、OAuth 2.0のトークン取得と更新、ジョブ完了のポーリング、再試行すべきエラーの判別を自分で書くことになります。書く量は多くありませんが、抜けが出やすいのは3番目です。何を再試行してよいかの判断は後の章で扱います。

クエリ実行をjobs.queryとjobs.insertのどちらで書くか

クエリを投げる方法は2つあり、公式のジョブ実行ドキュメントは両者の関係をはっきり書いています。jobs.insert がジョブを開始する基本のメソッドで、完了は jobs.get を繰り返して status を見る。jobs.query は、ジョブを作成して指定した時間だけ DONE 状態を定期的にポーリングするラッパーです。

jobs.queryはポーリングを内包した短時間クエリ向けの入口

数秒で終わるクエリなら jobs.query が短く書けます。タイムアウトまでに完了すれば結果がそのまま返り、間に合わなければジョブ参照だけが返るので、続けて jobs.getQueryResults を呼びます。BIツールの裏側や、画面からの単発集計のように応答時間が短い処理はこちらで十分でしょう。

jobs.insertはジョブIDを自分で決められる点で再実行に強い

バッチ処理や長時間のクエリは jobs.insert 側です。決め手はジョブIDを明示できること。公式は job_id か job_id_prefix を渡すことを勧めていて、安定したジョブ識別子を与えると再試行時の二重投入を防げます。ネットワークが切れて応答を取りこぼしても、同じIDで投げ直せばジョブは1つのままです。

観点 jobs.query jobs.insert
完了待ち 指定時間だけ内部で待つ jobs.getで自分が回す
ジョブID 自動採番 明示できる
向く処理 数秒で終わる単発集計 長時間バッチと再実行
失敗時の再送 二重実行の恐れ 同一IDで冪等

サービスアカウントの権限はジョブ側とデータ側とStorage側で分ける

プログラムから叩く以上、実行主体はサービスアカウントになります。ここでのつまずきは、BigQueryのIAMが「ジョブを実行する権限」と「データへ到達する権限」を分けている構造を知らずにロールを積むこと。さらにStorage APIは第3の権限を要求します。

クエリを流すだけの用途に渡す最小ロールは2つの組み合わせで足りる

集計クエリを投げて結果を読むだけのサービスアカウントには、roles/bigquery.jobUser と roles/bigquery.dataViewer の2枚を渡します。前者はプロジェクト内でジョブを実行する権限だけを持ち、データそのものには届かない。後者はテーブルデータの参照とメタデータの閲覧を許し、更新はできません。

用途 渡すロール
クエリ実行と結果参照 jobUser + dataViewer
テーブル作成と書き込み jobUser + dataEditor
Storage Readで大量読取 上記 + readSessionUser
転送構成の作成と管理 bigquery.admin相当

Storage APIを叩くroleは本体のロールとは別に付与する

Storage Read APIで読み取りセッションを張るには roles/bigquery.readSessionUser が要ります。dataViewer を持っていても、このロールがなければ CreateReadSession は通りません。「コンソールからは見えるのにプログラムからだけ失敗する」という症状の典型がこれです。切り分けは単純で、REST v2側のクエリが通るならデータ側の権限は足りていて、Storage APIの呼び出しだけが落ちるならセッション側のロールが欠けている。

鍵ファイルを配らずに済ませる認証へ寄せる手段が3つ用意されている

サービスアカウントのJSON鍵をリポジトリや実行環境に置く運用は、漏れたときの被害が大きく、失効の管理も手間がかかります。回避手段は3つ。Google Cloud上で動かすならサービスへ直接サービスアカウントを紐づけてADCに任せる、AWSやオンプレミスから叩くならWorkload Identity連携で一時的な資格情報に交換する、開発者の手元では自分のアカウントで gcloud のログインを済ませてADCに解決させる。いずれも長期の鍵をファイルとして持ちません。

レート制限の実数を押さえて指数バックオフと冪等なジョブIDで守る

本番で最初に踏むのはレート制限です。上限は公開されているので、実装前に数字を見ておけば設計で避けられます。

既定の上限は毎秒100リクエストでjobs.getだけ1,000まで

公式のトラブルシューティングは、大半のコアメソッドが1ユーザー1メソッドあたり毎秒100リクエストで、jobs.get は毎秒1,000リクエストだと示しています。ここから導ける設計は非対称です。ジョブの投入側は毎秒100を超えないよう束ねる。完了確認は10倍の余裕があるので、細かく回しても詰まりません。

書き込み側は別枠で、Storage Write APIの同時接続はマルチリージョンで既定10,000、単一接続あたりのスループットは少なくとも毎秒1MBです。アプリケーションが作ったストリームは同時接続1本のみで、既定ストリームだけが複数接続を張れます。並列度を上げたいときにどちらのストリームを選ぶかが、そのまま到達できる帯域を決める。

指数バックオフは再試行してよいエラーを選別してから掛けるもの

再試行してよいのは、レート超過(rateLimitExceeded)とバックエンドの一時障害です。構文エラーや権限不足を再送しても結果は変わらず、上限だけを消費します。クライアントライブラリは既定で選別と待機を組み込んでいますが、待ち時間の上限は処理の性格に合わせて明示するほうが安全です。

from google.api_core import retry

job = client.query(
    sql,
    job_id_prefix="daily_agg_",
    retry=retry.Retry(initial=1.0, maximum=60.0, multiplier=2.0, deadline=600.0),
)

ジョブIDを自分で決めておけば再送しても二重実行にはならない

再試行の設計で効くのは待ち時間よりジョブIDです。同じIDのジョブは1つしか作られないため、応答が返る前に接続が切れて投げ直した場合でも、実行は1回に収まります。日次バッチなら対象日を含むIDにしておくと、再実行しても重複しない。逆にIDを自動採番へ任せたまま再送すると、同じ集計が2本走り、書き込み先が追記設定なら行が二重になります。

クォータそのものが足りない場合は、リトライでは解決しません。Google Cloudコンソールから割り当ての引き上げを申請します。Storage Write APIについては、スループットの引き上げと同時接続数の引き上げを同じ比率で申請するのが公式の案内です。

どのAPI面を採るかとBigQuery APIを見送ってよい場面の条件

ここからは判断です。実装の選択肢が4系統もあると迷いますが、切り替えの閾値は量で決まります。

読み書きの量が閾値を超えたらStorage APIへ切り替える

読み取りは、1回の処理で取り出す行が数万行までならREST v2のジョブAPIで足ります。数十万行を超えたあたりからページネーションの往復が支配的になるので、Storage Read APIへ移してください。毎月300TiBの無料枠があるため、多くの社内用途では追加費用が出ないまま所要時間だけが縮みます。

書き込みは3段階です。日次や時間次でまとめて入れるならバッチ読み込みが無料で最も安い。数秒以内の反映が要るならStorage Write APIのgRPC版、それも重複を許さない処理ならcommitted型でオフセットを指定します。REST版のストリーミングinsertは、既存コードが依存している場合を除いて新規に選ぶ理由が薄い。単価が倍で、厳密1回の配信もありません。

自社で組むか外部に任せるかは権限設計と再試行の複雑さで決める

自力で進めてよい範囲ははっきりしています。呼び出し元が1系統で、扱うデータセットが1つか2つ、権限を渡す相手が同じチームに閉じているなら、クライアントライブラリで組んで問題ありません。

線を越えるのは3つの条件が重なったときです。呼び出し元が複数のシステムにまたがること、データセットごとに見せる相手を分ける必要があること、そして書き込みで重複が許されないこと。この3つが揃うと、サービスアカウントの分割方針とストリーム型の選択と再試行の冪等性を同時に設計する話になり、後から直すコストが跳ね上がる局面です。当社ではAPI開発・システム連携として、認証方式の選定から権限設計、再試行と監視を含めた連携基盤の構築を請けています。基盤全体の層構成から考える場合はデータ分析基盤構築・MLOps構築支援の範囲になり、体制の組み方はBigQuery導入の手順と体制の解説が参考になります。

BigQuery APIを見送ってよいのは3つの条件が揃った場面

逆に、APIを叩く実装を書かずに済ませたほうがよい場面もあります。第一に、取り込みたい元データが対応ソースの一覧にあるとき。転送構成を登録するだけで済むものへ自前のコードを書くのは、保守の対象を増やすだけです。第二に、出力先がダッシュボードだけのとき。BIツールから直接つなげば、閲覧者にBigQueryの権限を配らずに済みます。第三に、処理の中身がSQLで完結するとき。スケジュールクエリで回せる集計に、外側からジョブを投げるコードは要りません。

この3つのいずれにも当てはまらない、つまりアプリケーションの動作の一部としてBigQueryを読み書きする必要があるときに初めて、API実装が正味の価値を持ちます。判断の前段として、BigQuery自体を採るかどうかはBigQueryの仕組みと採用判断をまとめた解説を、基盤のどの層に置くかはデータ分析基盤の5層アーキテクチャの解説を先に見てください。SQLだけで学習まで完結させる道はBigQuery MLの解説に整理しています。

よくある質問

BigQuery APIの利用そのものに料金はかかりますか?

API呼び出しの回数に対する課金はありません。かかるのは処理した内容に対する費用で、クエリならスキャンしたバイト数、Storage Read APIなら読み取り量が1TiBあたり1.10ドル、Storage Write APIのgRPC版なら書き込み量が1GiBあたり0.025ドルです。それぞれに無料枠があり、Storage Readは請求先アカウントごとに毎月300TiB、Storage Writeは毎月2TiBまでは費用が出ません。バッチ読み込みとバッチエクスポートは共有スロットプールで無料です。

RESTを直接叩くのとクライアントライブラリはどちらが速いですか?

同じジョブAPIを呼ぶ限り、実行そのものの速度は変わりません。差が出るのは大量の行を取り出すときで、ページネーションで回すか、Storage Read APIで並列に読むかという経路の違いが所要時間を決めます。ライブラリの一部は結果サイズを見て自動的に高速な経路へ切り替えるため、同じコードのまま速くなる場合もある。速度を理由にRESTを直接叩く判断は、まず成立しません。

サービスアカウントの鍵ファイルを使わずにAPIを叩けますか?

叩けます。Google Cloud上で動くワークロードならサービスアカウントを紐づけるだけでADCが解決し、鍵ファイルは不要です。AWSやオンプレミスからならWorkload Identity連携で一時的な資格情報へ交換できます。開発者の手元では gcloud のログインで保存した資格情報がADCの探索先になるため、こちらも鍵は要りません。長期の鍵をファイルで持つ運用は、他に手段がない場合に限ってください。

ストリーミング書き込みで行が重複してしまうのを防げますか?

防げます。Storage Write APIのcommitted型ストリームでオフセットを指定すると、そのオフセットが次の追記位置と一致した場合にだけ処理が成立するため、再送しても重複しません。既定ストリームは最低1回の保証なので、再送時に同じ行が入る可能性があります。重複を許さない処理では、ストリーム型の選択とオフセット管理を最初から設計へ含めてください。

レート制限に当たったときはどう対処すればよいですか?

まず、再試行してよいエラーかを見分けます。レート超過と一時障害は指数バックオフで待って投げ直す、構文エラーや権限不足は再送せずに落とす。この選別を入れないと、上限を消費しながら同じ失敗を繰り返します。恒常的に上限へ張り付くようなら、リクエストを束ねて呼び出し回数そのものを減らすか、Google Cloudコンソールから割り当ての引き上げを申請してください。

関連記事

資料請求

RELATED POSTS 関連記事