- オンデマンドと BigQuery editions(Standard・Enterprise・Enterprise Plus)という 2 つのコンピュート課金モデルの違いと、損益分岐の考え方
- 論理ストレージ課金と物理ストレージ課金の違い、アクティブ/長期保存の 90 日ルール
- dry run・maximum bytes billed・カスタムクォータ・予算アラートという 4 層のコスト制御
- INFORMATION_SCHEMA.JOBS で高額クエリを特定し、請求データのエクスポートでコストを可視化する方法
- 「LIMIT はスキャン量を減らさない」「SELECT * は最悪手」という 2 つの誤解を、根拠込みで解体する
前提: 全ハンズオンがサンドボックスで完走可・無料枠内。
二つのコンピュート課金モデル — オンデマンドと 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)単価は次のとおりです。
| 機能・単価 | Standard | Enterprise | Enterprise 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 | 非対応 | 非対応 | 対応 |
| 月次 SLO | 99.9% 以上 | 99.99% 以上 | 99.99% 以上 |
スロットコミットメント(1 年・3 年)は Enterprise と Enterprise Plus だけが利用できます。Standard とオンデマンドにはコミットメントの購入枠自体がありません。コミットメントは 50 スロット単位・最低 50 スロットから購入し、リージョン単位の容量で、組織全体で共有できます。予約(reservation)は既定で 1 分単位の最低billing(秒課金・1 分未満は切り上げ)ですが、BigQuery fluid scaling にオプトインすると最低時間なしの秒単位課金になります。予約のベースラインを 0、最大スロット数だけを設定すれば、必要なときだけスロットが自動的にスケールする「オンデマンド的な使い方」も editions の中で実現できます。なお、既存の予約のエディションを変更したい場合は予約自体を削除して作り直す必要があります。
課金モデルの選び方をコスト制御の観点で整理すると、次のようになります。
| 比較軸 | オンデマンド | 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%) |
物理ストレージ課金を選ぶと、データが圧縮されている分だけ単価は上がっても総量が小さくなるため、圧縮率の高いデータ(繰り返しの多い文字列の列など)では有利になります。逆に元々あまり圧縮できないデータでは論理課金の方が安くなることが多いです。どちらが得かは INFORMATION_SCHEMA.TABLE_STORAGE ビューの total_logical_bytes と total_physical_bytes を比べれば実測できます(ハンズオン 7-2 で行います)。物理ストレージ課金にはもう一つ注意点があり、タイムトラベルとフェイルセーフのストレージも課金対象になります(論理課金では無償)。既定のタイムトラベル期間は 7 日で、物理課金を使う場合はこの期間を短縮するとコストを抑えられます。
90 日以上変更されていないテーブル(またはパーティション)は自動的に長期保存の単価に切り替わります。ここで重要なのは「何がタイマーをリセットするか」です。テーブルへのロード・コピー先としての書き込み・クエリ結果の書き込み先としての利用・DML・CREATE OR REPLACE TABLE などの 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 はクエリを実行せずに処理バイト数を見積もります。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 タブを使ってください。これらは無料です。
コストを追跡する側の道具として、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 日かかる点に注意してください。
ハンズオン
公開データセットに対して dry run で処理量を確認し、意図的に低い maximum bytes billed を設定してクエリを失敗させたあと、妥当な値で成功させます。サンドボックスで完走可・無料枠内(スキャン量は数百 KB 程度)。
- 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 をメモしておきます。
- 意図的に低い 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 で確認した N 以上の値を指定し、成功させます。
bq query --maximum_bytes_billed=10000000 --use_legacy_sql=false \
'SELECT word, corpus
FROM `bigquery-public-data.samples.shakespeare`
WHERE corpus = "hamlet"'
期待される出力: hamlet に登場する単語の一覧が正常に返ります。
後片付け: 今回は新規リソースを作成していないため不要です。
公開データを演習用データセットにコピーし、論理バイト数と物理バイト数を比べて、どちらの課金モデルが有利かを実測します。サンドボックスで完走可・無料枠内(コピー量は数百 MB 程度の見込み。実行前に dry run で確認してください)。
- 演習用データセットを作成し、圧縮の効きやすい公開テーブルをコピーします。
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`;
- 作成したテーブルの論理バイト数と物理バイト数を比較します。
-- 処理: メタデータの参照のみ(無料枠内)
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)に切り替えるメリットが大きくなります。
- 比率をもとに、データセットの課金モデルを物理に切り替えます(反映まで 24 時間かかります)。
ALTER SCHEMA `PROJECT_ID.handson_ch07`
SET OPTIONS(
storage_billing_model = 'PHYSICAL');
後片付け:
bq rm -r -f -d PROJECT_ID:handson_ch07
自分のプロジェクトのジョブ履歴から、課金バイト数の多いクエリを特定します。サンドボックスで完走可・無料枠内(自プロジェクトのメタデータ参照のみ)。
- これまでのハンズオンで実行したジョブの中から、課金バイト数上位 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 の見積もりが大きくなりすぎることがあるため、必ず期間を絞り込んでください。
後片付け: 今回は新規リソースを作成していないため不要です。
つまずきポイント
ALTER SCHEMA ... SET OPTIONS(storage_billing_model = ...) は即座には反映されず 24 時間かかり、しかも一度変更すると次の変更まで 14 日間は再変更できません。「やっぱり戻したい」と思ってもすぐには戻せないため、切り替え前に TABLE_STORAGE ビューでの実測を必ず済ませてください。理解度チェック
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 はストレージ課金の話でクエリのスキャン量とは無関係です。
まとめと次章へ
- オンデマンド($6.25/TiB、US)と BigQuery editions(Standard $0.04・Enterprise $0.06・Enterprise Plus $0.10、いずれも slot-時間、US 従量)はいつでも切り替えられ、混在もできる。損益分岐点は固定値ではなくワークロード次第
- ストレージ課金は論理($0.02/GiB)と物理($0.04/GiB、いずれも長期保存で 50% 引き)をデータセット単位で選べるが、オンデマンドのクエリ課金は常に論理バイト基準のまま変わらない
- コスト制御は dry run(見積もり)→ maximum bytes billed(クエリ単位のハードキャップ)→ カスタムクォータ(日次のハードキャップ)→ 予算アラート(月次の通知のみ)という異なる層で組み合わせる
- 「LIMIT は非クラスタ化テーブルでは効かない」「SELECT * は最悪手」は、カラムナストレージの課金の仕組みそのものから来る誤解
- INFORMATION_SCHEMA.JOBS / TABLE_STORAGE と請求データのエクスポートで、コストを事後にも継続的に可視化できる