# BigQuery のコストはなぜ暴れやすいのか
BigQuery は速く、扱いやすく、分析基盤として強力です。だからこそ危ないです。便利すぎるサービスは、設計より先に「とりあえず動かす」が標準になりやすいからです。
この記事では、BigQuery のコストが暴れやすい理由を、SQL の書き方だけでなく、Partitioning、Clustering、実行前見積もり、IAM 権限、データモデリングまで含めて整理します。対象は、Google Cloud 上で BigQuery を使い始めたチーム、または Looker Studio などの BI 利用が増えて請求が気になり始めたチームです。
先に結論
先に結論を言うと、BigQuery のコスト管理は「後で SQL を最適化する」だけでは足りません。時系列データは Partitioning 前提で置き、よく使う絞り込み条件に合わせて Clustering を決め、実行前に bytes processed の見積もりを見る必要があります。さらに、全員に重いクエリを自由実行できる IAM 権限を渡さず、raw / staging / mart を分けて BI が毎回 raw を読まない構造にするべきです。
BigQuery のコスト問題は、SQL テクニック単体ではなく、データの置き方と人の使い方を一緒に設計できているかでかなり決まります。
なぜ BigQuery はコストが暴れやすいのか
BigQuery はオンデマンド料金の場合、基本的にクエリで処理したデータ量がコストに効きます。ユーザーの感覚では「少し確認しただけ」でも、裏側では大きなテーブルを広く読んでいることがあります。
たとえば、調査のたびに `SELECT *` を実行する、日付条件なしで巨大なログテーブルを読む、JOIN 前に不要列を落とさない、Looker Studio のダッシュボードが毎回フルスキャンする、といったことはよく起きます。どれも悪意のある操作ではありません。むしろ普通の分析作業です。だからこそ、BigQuery のコスト事故は「高度な使い方をしたから」ではなく、普通に便利に使っていたら膨らんだ、という形で起きます。
まず Partitioning を前提に考える
BigQuery で最初に見るべきは、SQL の細かい書き方よりもテーブル設計です。特にイベントログ、監査ログ、アクセス履歴、売上明細のように時系列で増えるデータは、Partitioning なしで運用すると後から苦しくなります。
典型的に危な��のは、`created_at` はあるが partitioned table ではない、パーティション列を関数で包み partition pruning が効きにくい、直近7日だけ見ればよいのに年間データを読む、BI 用の定例集計でも raw テーブルを直接参照している、という状態です。
例えば、発想としてはこうです。
```sql
-- 雑に全期間を読む例
SELECT *
FROM analytics.events;
-- 期間と列を絞って読む例
SELECT event_date, event_name, user_id
FROM analytics.events
WHERE event_date BETWEEN DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
AND CURRENT_DATE();
```
大事なのは、この SQL だけを覚えることではありません。日付で絞る運用なら、日付で絞れるテーブルとして置くことです。BigQuery では「どの列を読むか」以前に、「どこまで読ませる構造にしているか」がコストに直結します。
Clustering は魔法ではないが効く
Partitioning の次に効いてくるのが Clustering です。ただし、Clustering を入れれば自動的に全部安くなるわけではありません。よく使う絞り込みや集計のパターンと噛み合って初めて効きます。
| 典型クエリ | 相性がよい Clustering 候補 |
|---|---|
| 顧客単位で頻繁に参照する | customer_id |
| テナント単位で分析する | tenant_id |
| イベント種別で集計する | event_type |
| 地域や事業部ごとに切る | region, business_unit |
逆に、毎回違う列で雑に検索する運用なら、Clustering を入れても効果は限定的です。BigQuery のテーブルを作るときに「このデータは誰が、どの条件で読むのか」を先に確認するべきです。
実行前見積もりを文化にする
BigQuery では、クエリ実行前に bytes processed の見積もりを確認できます。実務では、まず実行前にスキャン量を見る、想定より大きければ列・期間・JOIN 条件を見直す、よく使うクエリは保存やレビュー対象にする、ダッシュボード系は集計済み mart テーブルに逃がす、という順序が安全です。
「とりあえず回してから考える」を許していると、分析チームの問題ではなく運用ルールの問題になります。BigQuery は速いので、失敗にもすぐ気づけません。請求で気づく。地味に最悪です。
IAM とデータモデリングを甘く見ない
BigQuery のコスト管理は、技術だけでなく IAM 設計の問題でもあります。全員が本番級 dataset に対して自由に重いクエリを打てる状態なら、いずれ請求は荒れます。閲覧専用のつもりで広い実行権限を渡している、開発用と本番用の dataset が分かれていない、service account の利用先が整理されていない、といった状態は危険です。
また、BigQuery は「生データをそのまま置いて後で全部読めばいい」と思われがちですが、その運用は長く続きません。raw は取り込んだまま保持し、staging で型変換や正規化を行い、mart で BI や定例分析向けに再構成する。この分離をしておくと、Looker Studio や Looker から巨大な raw テーブルを直接叩く回数を減らせます。
よくある失敗パターン
小さいうちは安いから設計を後回しにする。これはよくあります。初期は問題にならないので、ログ量や利用者数が増えたときに雑なテーブル設計がそのまま請求へ跳ね返ります。
重い SQL を書いた人だけを責めるのも危険です。もちろんクエリ品質は重要です。ただ、Partitioning されていない巨大テーブル、雑な IAM、共通クエリ不在の環境を放置していれば、誰が使っても事故ります。
BI のクエリ負荷を見ないのも定番です。Looker Studio などの BI ツールは便利ですが、裏側ではクエリが走ります。更新頻度、閲覧人数、フィルタ条件の作り方によっては、手動クエリよりも BI の方がじわじわ効きます。
まとめ
BigQuery のコスト問題は、SQL の小手先だけでは止まりません。本当に見るべきなのは、Partitioning で読む範囲を狭められるか、Clustering が実際のクエリ傾向と合っているか、実行前見積もりを見る文化があるか、IAM と dataset の境界が整理されているか、BI 用の mart を用意しているか、という土台です。
BigQuery で請求が荒れが��なチームは、たいてい「無駄なクエリが多い」のではなく、無駄が出やすい使い方を標準にしてしまっています。先に直すべきなのは SQL そのものよりも、その SQL が生まれる前提です。