BigQuery ハンズオン教科書|2026-08 版
第 7 章 サンドボックスで完走可

料金モデルとコスト管理

オンデマンドとエディションを理解し、課金事故を構造的に防ぐ

この章で学ぶこと

前提: 全ハンズオンがサンドボックスで完走可・無料枠内。

二つのコンピュート課金モデル — オンデマンドと editions

BigQuery のコンピュート(クエリ実行)には 2 つの課金モデルがあります。オンデマンドは処理したバイト数に応じて課金され、BigQuery editions(キャパシティベース課金)はスロット時間で課金されます。どちらもいつでも切り替えられ、プロジェクト単位で両方を組織内に混在させることもできます。

オンデマンドは既定のモデルで、2026-08 時点で米国(US マルチリージョン)は 1 TiB あたり 6.25 米ドル、月間最初の 1 TiB は無料です。この無料枠は請求先アカウント単位で共有される点に注意してください(後述のつまずきポイント参照)。課金の丸めルールも押さえておく必要があります。処理バイト数は MB 単位に切り上げられ、クエリが参照するテーブル 1 つあたり最低 10 MB、クエリ全体でも最低 10 MB が課金対象になります。オンデマンドでは 1 プロジェクトあたり最大 2,000 スロットを他のクエリと共有する形でおおむね利用でき、小さいクエリを速く終わらせるために一時的にこの上限を超えてバーストすることもあります。

editions はスロット(仮想 CPU)を時間単位で買い切るモデルです。Standard・Enterprise・Enterprise Plus の 3 エディションがあり、US(マルチリージョン)の従量(Pay as you go)単価は次のとおりです。

機能・単価StandardEnterpriseEnterprise Plus
スロット時間単価(従量、US)$0.04 / slot-時間$0.06 / slot-時間$0.10 / slot-時間
1 年コミットメント(US)$0.036$0.054$0.09
3 年コミットメント(US)$0.032$0.048$0.08
BigQuery ML・Graph・継続クエリ非対応対応対応
マネージド DR・Assured Workloads非対応非対応対応
月次 SLO99.9% 以上99.99% 以上99.99% 以上

スロットコミットメント(1 年・3 年)は Enterprise と Enterprise Plus だけが利用できます。Standard とオンデマンドにはコミットメントの購入枠自体がありません。コミットメントは 50 スロット単位・最低 50 スロットから購入し、リージョン単位の容量で、組織全体で共有できます。予約(reservation)は既定で 1 分単位の最低billing(秒課金・1 分未満は切り上げ)ですが、BigQuery fluid scaling にオプトインすると最低時間なしの秒単位課金になります。予約のベースラインを 0、最大スロット数だけを設定すれば、必要なときだけスロットが自動的にスケールする「オンデマンド的な使い方」も editions の中で実現できます。なお、既存の予約のエディションを変更したい場合は予約自体を削除して作り直す必要があります。

月額コスト オンデマンド エディション(固定つみあげ) 月間スキャン量 → 損益分岐点 実際の位置はワークロード次第(slot estimatorで確認)
図 7-1 オンデマンドはスキャン量に比例して費用が増え、エディションはスロットを買い切るため費用がほぼ一定になる。両者が交差する点が損益分岐だが、正確な位置はクエリのスロット効率に依存するため、実測や BigQuery スロット推定ツールで確認する。
実務の視点: 「月間 ○ TiB を超えたら editions」のような一律の閾値は存在しません。同じバイト数を処理するクエリでも、複雑な JOIN や集計が多いクエリほど 1 バイトあたりに使うスロット時間が長くなるため、損益分岐点はワークロードのスロット効率に大きく依存します。オンデマンドで運用しながら BigQuery スロット推定ツールで過去の実績からコミットメントのサイジングを確認するのが、机上の計算より確実です。

課金モデルの選び方をコスト制御の観点で整理すると、次のようになります。

比較軸オンデマンドeditions(キャパシティ)
課金の単位TiB(スキャンしたバイト数)slot-時間
最小/最大キャパシティプロジェクトあたり最大 2,000 スロットを共有予約あたり最小 50 スロット、リージョンのクォータまで拡張可能
コスト制御プロジェクト/ユーザー単位のカスタムクォータ(ハードキャップ)予約ごとにスロット数の上限を設定
設定設定不要スロット予約を作成しプロジェクトに割り当て
割引なし(従量のみ)Enterprise/Enterprise Plus は 1 年・3 年コミットメントで割引
予測可能性使用量に応じて請求額が変動ベースライン+コミットメントで予測しやすい

ストレージ課金 — 論理 vs 物理、アクティブ vs 長期保存

BigQuery のストレージ課金は、データセット単位で論理(圧縮前)と物理(圧縮後)のどちらかを選べます。2026-08 時点の US(マルチリージョン)の単価は次のとおりです(最初の 10 GiB は毎月無料)。

区分アクティブ(直近 90 日以内に変更)長期保存(90 日以上不変)
論理ストレージ課金$0.02 / GiB / 月$0.01 / GiB / 月(-50%)
物理ストレージ課金$0.04 / GiB / 月$0.02 / GiB / 月(-50%)
テーブルの実データ 論理を選択 物理を選択 論理ストレージ課金 圧縮前のバイト数で計算 $0.02/GiB/月(アクティブ) 物理ストレージ課金 圧縮後のバイト数で計算 $0.04/GiB/月(アクティブ) オンデマンドのクエリ課金は常に論理バイトが基準
図 7-2 同じテーブルでも、論理(圧縮前)バイトで課金するか物理(圧縮後)バイトで課金するかをデータセット単位で選べる。ただし選択が変えるのはストレージ費用だけで、オンデマンドクエリの課金は常に論理バイト基準のまま変わらない。

物理ストレージ課金を選ぶと、データが圧縮されている分だけ単価は上がっても総量が小さくなるため、圧縮率の高いデータ(繰り返しの多い文字列の列など)では有利になります。逆に元々あまり圧縮できないデータでは論理課金の方が安くなることが多いです。どちらが得かは INFORMATION_SCHEMA.TABLE_STORAGE ビューの total_logical_bytes と total_physical_bytes を比べれば実測できます(ハンズオン 7-2 で行います)。物理ストレージ課金にはもう一つ注意点があり、タイムトラベルとフェイルセーフのストレージも課金対象になります(論理課金では無償)。既定のタイムトラベル期間は 7 日で、物理課金を使う場合はこの期間を短縮するとコストを抑えられます。

実務の視点: ストレージ課金モデルを切り替えても、クエリの性能には影響しません。判断材料は純粋にコストです。TABLE_STORAGE ビューで実際の圧縮率を測ってから選ぶのが安全で、「なんとなく物理の方が新しいから」で切り替えるのは避けてください。

90 日以上変更されていないテーブル(またはパーティション)は自動的に長期保存の単価に切り替わります。ここで重要なのは「何がタイマーをリセットするか」です。テーブルへのロード・コピー先としての書き込み・クエリ結果の書き込み先としての利用・DML・CREATE OR REPLACE TABLE などの DDL・ストリーミング挿入はいずれもタイマーを 0 日にリセットします。一方、単にクエリで読む・ビューを作る・エクスポートする・別テーブルへコピーする(コピー元として)・テーブルのメタデータ(説明やラベル)を更新するだけではタイマーはリセットされません。

アクティブストレージ(0〜89 日) $0.02/GiB/月 長期保存(90 日以上不変) $0.01/GiB/月(-50%) 0 日 90 日 ロード・DML・DDL・ストリーミングで 0 日にリセット リセットしない: クエリで読む・ビュー作成・エクスポート・コピー元利用
図 7-3 90 日間変更のないテーブルは自動的に長期保存の割引価格に移行する。ロード・DML・DDL・ストリーミング挿入はタイマーを 0 日に巻き戻すが、読み取り系の操作はリセットしない。

ストレージ課金モデルを切り替えるには、コンソールでデータセットの詳細から Storage billing model を変更するか、次のように操作します。

-- SQL(DDL)
ALTER SCHEMA `PROJECT_ID.handson_ch07`
SET OPTIONS(
  storage_billing_model = 'PHYSICAL');

-- bq コマンド
bq update -d --storage_billing_model=PHYSICAL PROJECT_ID:handson_ch07

BILLING_MODEL には LOGICAL か PHYSICAL を指定します。変更が反映されるまでには 24 時間かかり、一度変更すると次に変更できるまで 14 日間の待機期間があります(後述のつまずきポイント参照)。

コスト制御の道具箱と誤解の解体

コスト事故を防ぐ道具は、発動するタイミングの異なる 4 層に分けて考えると整理しやすくなります。

実行前 ① dry run 処理量を見積もる 次へ 実行時(クエリ単位) ② 上限バイト数指定 超過で無課金失敗 次へ 日次 ③ カスタムクォータ プロジェクトかユーザー単位 次へ 月次 ④ 予算アラート 通知のみ(止めない)
図 7-4 dry run は実行前の見積もり、maximum bytes billed はクエリ単位のハードキャップ、カスタムクォータは日次のハードキャップ、予算アラートは月次の通知に過ぎない。①〜③は実行を止められるが、④は止められない点が本質的に違う。

① dry run はクエリを実行せずに処理バイト数を見積もります。bq CLI では次のように使います。

bq query --use_legacy_sql=false --dry_run \
'SELECT word, corpus
 FROM `bigquery-public-data.samples.shakespeare`
 WHERE corpus = "hamlet"'

成功すると「Query successfully validated. Assuming the tables are not modified, running this query will process N bytes of data.」という応答が返ります。BigQuery Studio のクエリエディタでも、クエリを入力した時点で右上に同様の見積もりが自動表示されます。

② maximum bytes billed は、見積もりバイト数が指定した上限を超えた場合にクエリ自体を無課金で失敗させる仕組みです。

bq query --maximum_bytes_billed=1000000 --use_legacy_sql=false \
'SELECT word FROM `bigquery-public-data.samples.shakespeare`'

上限を超えると次のようなエラーになり、課金は発生しません。

Error: Query exceeded limit for bytes billed: 1000000. 10485760 or higher
required.

コンソールでは、クエリエディタの「編集」→「クエリの設定」→「詳細オプション」から Maximum bytes billed を設定します。ただしクラスタ化テーブルに対しては、この見積もりは実際の課金バイト数より大きめに出ることがあるため、実際には収まるはずのクエリが失敗することがあります(つまずきポイント参照)。

③ カスタムクォータは、オンデマンドの利用で 1 日あたりに処理できるデータ量そのものに上限をかけます。プロジェクト単位の QueryUsagePerDay(既定値 200 TiB/日)と、ユーザー単位の QueryUsagePerUserPerDay(既定値は無制限)の 2 種類があり、Google Cloud コンソールの「IAM と管理」→「割り当て」で BigQuery API を絞り込み、対象のクォータを編集して「無制限」のチェックを外し、TiB 単位の値を入力して申請します。上限に達すると、それ以降のクエリは「Custom quota exceeded: Your usage exceeded the custom quota for QueryUsagePerDay」(ユーザー単位なら QueryUsagePerUserPerDay)というエラーで実行そのものがブロックされます。maximum bytes billed と違い、クエリ個別ではなく日次の累計に対するハードキャップです。

④ 予算アラートは Cloud Billing の予算機能で、実績が設定したしきい値を超えるとメール通知が届きます。ここまでの 3 つと違い、予算アラートはクエリの実行を一切止めません。あくまで人間に気づかせるための通知です。

これらの土台の上に、よくある 2 つの誤解を解いておきます。

誤解 1: 「LIMIT を付ければ課金は減る」。非クラスタ化テーブルに対しては誤りです。BigQuery はカラムナ形式でデータを保持しているため、クエリで選択した列の総データ量に応じて課金され、LIMIT で結果行数を絞っても、選択した列は最後まで全行スキャンされてから絞り込まれます。クラスタ化テーブルに対しては話が変わります。クラスタ列へのフィルタと組み合わさっている場合、十分な結果が集まった時点でスキャンを打ち切れるため、実際にスキャンバイト数が減ることがあります。

誤解 2: 「SELECT * は無難な書き方」。カラムナストレージでは、選択した列のデータ型に基づくバイト数だけが課金対象になります。SELECT * は常に全列を読むため、必要な列だけを指定するクエリに比べて最悪のケースになりがちです。テーブルの中身を確認したいだけなら、クエリで探索するのではなく bq head コマンドやコンソールの Preview タブを使ってください。これらは無料です。

非クラスタ化テーブル + LIMIT 10 スキャン: 100%(全バイトを課金) クラスタ化テーブル + LIMIT 10 スキャン プルーニングでスキップ 十分な行が集まり停止 結論: LIMIT 単体では効かない。効くのはクラスタリング/パーティションで読む範囲自体を減らせたときだけ
図 7-5 非クラスタ化テーブルでは LIMIT を付けてもテーブル全体がスキャン対象のままだが、クラスタ化テーブルでは十分な行が集まった時点でスキャンを打ち切れるため、実際にスキャンバイト数が減ることがある。

コストを追跡する側の道具として、INFORMATION_SCHEMA.JOBS ビューが役立ちます。region-us のようなリージョン修飾子を必ず付ける必要があり、直近 180 日分のジョブ履歴を保持します。参照には roles/bigquery.user と roles/bigquery.resourceViewer(権限としては bigquery.jobs.listAll と bigquery.jobs.create)が必要です。job_id・user_email・query・total_bytes_billed・total_slot_ms といった列から、誰がどのクエリでどれだけ課金されたかを追跡できます。請求データそのものを分析したい場合は、Cloud Billing のデータを BigQuery へエクスポートする機能も使えます。標準の使用コストデータ(SKU・プロジェクト・ラベル・ロケーション単位のコストと使用量)に加えて、仮想マシンやディスクなど個別リソース単位まで含む詳細使用コストデータ、SKU の価格設定情報そのものを含む価格設定データの 3 種類を個別に有効化できます。初回設定時は過去分のデータが出そろうまで最大 5 日かかる点に注意してください。

ハンズオン

ハンズオン 7-1|dry run と maximum bytes billed でクエリを実行前に止める

公開データセットに対して dry run で処理量を確認し、意図的に低い maximum bytes billed を設定してクエリを失敗させたあと、妥当な値で成功させます。サンドボックスで完走可・無料枠内(スキャン量は数百 KB 程度)。

  1. dry run で処理バイト数を見積もります。
bq query --use_legacy_sql=false --dry_run \
'SELECT word, corpus
 FROM `bigquery-public-data.samples.shakespeare`
 WHERE corpus = "hamlet"'

期待される出力: 「Query successfully validated. ... will process N bytes of data.」というメッセージ。表示された N をメモしておきます。

  1. 意図的に低い maximum bytes billed を指定し、クエリを失敗させます。
bq query --maximum_bytes_billed=1000000 --use_legacy_sql=false \
'SELECT word, corpus
 FROM `bigquery-public-data.samples.shakespeare`
 WHERE corpus = "hamlet"'

期待される出力: Error: Query exceeded limit for bytes billed: 1000000. N or higher required. というエラー。このクエリは無課金です。

  1. 手順 1 で確認した N 以上の値を指定し、成功させます。
bq query --maximum_bytes_billed=10000000 --use_legacy_sql=false \
'SELECT word, corpus
 FROM `bigquery-public-data.samples.shakespeare`
 WHERE corpus = "hamlet"'

期待される出力: hamlet に登場する単語の一覧が正常に返ります。

後片付け: 今回は新規リソースを作成していないため不要です。

ハンズオン 7-2|INFORMATION_SCHEMA.TABLE_STORAGE で論理/物理ストレージを比較する

公開データを演習用データセットにコピーし、論理バイト数と物理バイト数を比べて、どちらの課金モデルが有利かを実測します。サンドボックスで完走可・無料枠内(コピー量は数百 MB 程度の見込み。実行前に dry run で確認してください)。

  1. 演習用データセットを作成し、圧縮の効きやすい公開テーブルをコピーします。
bq mk --location=US --dataset PROJECT_ID:handson_ch07

CREATE OR REPLACE TABLE `PROJECT_ID.handson_ch07.usa_names` AS
SELECT name, gender, year, state, number
FROM `bigquery-public-data.usa_names.usa_1910_current`;
  1. 作成したテーブルの論理バイト数と物理バイト数を比較します。
-- 処理: メタデータの参照のみ(無料枠内)
SELECT
  table_name,
  total_logical_bytes,
  total_physical_bytes,
  ROUND(total_logical_bytes / total_physical_bytes, 2) AS compression_ratio
FROM `region-us`.INFORMATION_SCHEMA.TABLE_STORAGE
WHERE table_schema = 'handson_ch07'
  AND table_name = 'usa_names';

期待される出力: total_logical_bytes より total_physical_bytes の方が小さく、氏名のような繰り返しの多い文字列データでは compression_ratio が 1 を大きく上回ります。この比率が高いほど、物理ストレージ課金($0.04/GiB)に切り替えるメリットが大きくなります。

  1. 比率をもとに、データセットの課金モデルを物理に切り替えます(反映まで 24 時間かかります)。
ALTER SCHEMA `PROJECT_ID.handson_ch07`
SET OPTIONS(
  storage_billing_model = 'PHYSICAL');

後片付け:

bq rm -r -f -d PROJECT_ID:handson_ch07
ハンズオン 7-3|INFORMATION_SCHEMA.JOBS で高額クエリ Top10 を洗い出す

自分のプロジェクトのジョブ履歴から、課金バイト数の多いクエリを特定します。サンドボックスで完走可・無料枠内(自プロジェクトのメタデータ参照のみ)。

  1. これまでのハンズオンで実行したジョブの中から、課金バイト数上位 10 件を抽出します。
-- 処理: メタデータの参照のみ(無料枠内)
SELECT
  job_id,
  user_email,
  creation_time,
  total_bytes_billed,
  total_slot_ms,
  query
FROM `region-us`.INFORMATION_SCHEMA.JOBS
WHERE job_type = 'QUERY'
  AND state = 'DONE'
  AND creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
ORDER BY total_bytes_billed DESC
LIMIT 10;

期待される出力: 直近 7 日間に実行したクエリのうち、課金バイト数が多い順に最大 10 件(job_id・実行者・実行時刻・課金バイト数・スロット消費量・クエリ本文)。creation_time でのフィルタを外すと、パーティションプルーニングが効かず dry run の見積もりが大きくなりすぎることがあるため、必ず期間を絞り込んでください。

後片付け: 今回は新規リソースを作成していないため不要です。

つまずきポイント

無料枠はプロジェクト単位ではない: 月間 1 TiB のクエリ無料枠と 10 GiB のストレージ無料枠は、料金表に「per 1 month / account」と明記されているとおり請求先アカウント単位で共有されます。同じ請求先アカウントに複数のプロジェクトをぶら下げている場合、無料枠は全プロジェクトで食い合うため、「このプロジェクトではまだ無料枠のはず」という思い込みは危険です。
maximum bytes billed がクラスタ化テーブルで不当に失敗する: クラスタ化テーブルでは見積もりバイト数が実際の課金バイト数より大きめに出ることがあります。ぎりぎりの値を設定すると、本来は上限内に収まるはずのクエリが失敗することがあるため、見積もりにはある程度の余裕を持たせてください。
ストレージ課金モデルの切り替えには待機期間がある: ALTER SCHEMA ... SET OPTIONS(storage_billing_model = ...) は即座には反映されず 24 時間かかり、しかも一度変更すると次の変更まで 14 日間は再変更できません。「やっぱり戻したい」と思ってもすぐには戻せないため、切り替え前に TABLE_STORAGE ビューでの実測を必ず済ませてください。
カスタムクォータと予算アラートを混同する: カスタムクォータは上限に達した瞬間にクエリの実行そのものをブロックするハードキャップです。予算アラートはあくまで実績を通知するだけで、実行は一切止めません。「予算アラートを設定したから安心」ではなく、実行を止めたいなら maximum bytes billed かカスタムクォータが必要です。

理解度チェック

Q1. オンデマンドと BigQuery editions のどちらを選ぶべきか、判断の基準は?

固定の閾値はなく、コストの予測可能性への要求とワークロードのスロット効率で判断します。請求額を安定させたいならコミットメント付きの editions、スパイクの少ない小〜中規模の利用ならオンデマンドが単純です。正確な損益分岐点はクエリの複雑さに依存するため、BigQuery スロット推定ツールで実測するのが確実です。

Q2. 論理ストレージ課金と物理ストレージ課金の違いと、選択の基準を説明してください。

論理は圧縮前のバイト数、物理は圧縮後のバイト数で課金されます(US では論理 $0.02/GiB・物理 $0.04/GiB、いずれも長期保存で 50% 引き)。圧縮率の高いデータほど物理課金が有利ですが、物理課金ではタイムトラベル/フェイルセーフのストレージも課金対象になります。どちらが得かは INFORMATION_SCHEMA.TABLE_STORAGE で実測してから決めるべきで、切り替えには反映まで 24 時間、次の変更まで 14 日のクールダウンがあります。

Q3. 「LIMIT はコストを下げる」「SELECT * は無難」という 2 つの誤解を、それぞれ正しく説明してください。

非クラスタ化テーブルでは LIMIT は課金バイト数を一切減らしません(全行スキャン後に結果だけ絞る)。クラスタ化テーブルではクラスタ列のフィルタと組み合わせれば、十分な行が集まった時点でスキャンを打ち切れるため実際に減ることがあります。SELECT * はカラムナストレージの特性上、必要な列だけを選ぶクエリより常に多くのバイトを読むため、コスト最適化の観点では避けるべきです。

Q4.(シナリオ)毎月のスキャン量が非常に大きく変動も少ないため、経理から「来月の請求額を事前に確定させたい」と言われている。最も適した施策は?
A. オンデマンドのままカスタムクォータを設定する B. Enterprise editions で 1 年または 3 年のスロットコミットメントを購入する C. すべてのクエリに maximum bytes billed を設定する D. 予算アラートのしきい値を下げる

B。コミットメントはスロット時間の単価を先に確定させる仕組みで、スキャン量が安定していれば請求額の予測可能性が最も高まります。A はハードキャップで利用を止めるだけで金額を確定させません。C は個々のクエリの失敗を防ぐ機能で予算の確定とは無関係です。D は通知のしきい値を変えるだけで実際のコストには影響しません。

Q5.(シナリオ)特定の 1 本の重いクエリが誤って巨大なテーブルを全スキャンし、数万円の課金が発生する事故を未然に防ぎたい(クエリの実行自体を止めたい)。最も直接的な対策は?
A. 予算アラートを設定する B. INFORMATION_SCHEMA.JOBS を毎朝確認する C. maximum bytes billed をクエリまたはプロジェクトの既定値に設定する D. ストレージ課金モデルを物理に変更する

C。maximum bytes billed は見積もりバイト数が上限を超えた時点でクエリ自体を無課金で失敗させる、実行前にブロックできる唯一の手段です。A は通知のみで実行は止まりません。B は事後の発見にしかなりません。D はストレージ課金の話でクエリのスキャン量とは無関係です。

まとめと次章へ