ふくふくHukuhuku Inc.
EP.06Democracy 13分公開: 2026-05-10

クエリ予算と負荷隔離:「コスト爆発」を構造的に防ぐ

民主化が進むと「ある日 bigquery 請求が10倍」「営業時間中に snowflake が詰まって全社の分析が止まる」が起きる。クエリ予算・タイムアウト・ワークロード隔離・自動アラートで構造的に防ぐ実装パターン。

#bigquery#snowflake#コスト管理#ワークロード隔離
CO📔 Google Colab で開く(上から順にセルを実行)
シェア

「使ってもらいたい」と「コストを管理したい」は両立する。本記事では、民主化のスケールに耐える コスト隔離・負荷隔離の実装パターンを、 / の両方でカバーします。

1. クエリ単位の上限を切る

BigQuery: maximum_bytes_billed

ジョブ単位で課金スキャン上限を設定
Python
from google.cloud import bigquery
bq = bigquery.Client()ONE_GB = 10 ** 9
# このクエリは絶対に 10 GB 以上スキャンさせないconfig = bigquery.QueryJobConfig(maximum_bytes_billed=10 * ONE_GB)job = bq.query("SELECT ... FROM events ...", job_config=config)
# 上限超過時は QueryJobConfigError がスロー → アプリ側でハンドリング

Snowflake: STATEMENT_TIMEOUT_IN_SECONDS / RESOURCE_MONITOR

Snowflake のクエリ最大実行時間 + クレジット予算
SQL
-- 個別ロールへのタイムアウトALTER ROLE BI_USERS SET STATEMENT_TIMEOUT_IN_SECONDS = 600;
-- ウェアハウス単位のクレジット監視CREATE OR REPLACE RESOURCE MONITOR rm_bi_warehouse  WITH CREDIT_QUOTA = 100  -- 月あたり 100 クレジット  TRIGGERS    ON 75 PERCENT DO NOTIFY    ON 100 PERCENT DO SUSPEND    ON 110 PERCENT DO SUSPEND_IMMEDIATE;
ALTER WAREHOUSE BI_WH SET RESOURCE_MONITOR = rm_bi_warehouse;

2. ワークロード隔離(ノイジーネイバー対策)

「営業時間中に分析者の重いクエリで全社の run が止まる」を防ぐには、ワークロードを物理的に分けます。

隔離手段粒度
BigQueryReservation + Assignmentプロジェクト × ジョブタイプ
SnowflakeWarehouse 分離ロール / 用途
RedshiftWLM Queueユーザグループ
Snowflake で「夜間バッチ」「対話的BI」「アドホック」を別 Warehouse に
SQL
CREATE WAREHOUSE BATCH_WH    WITH WAREHOUSE_SIZE = 'LARGE'  AUTO_SUSPEND = 60   AUTO_RESUME = TRUE;CREATE WAREHOUSE BI_WH       WITH WAREHOUSE_SIZE = 'MEDIUM' AUTO_SUSPEND = 60   AUTO_RESUME = TRUE;CREATE WAREHOUSE ADHOC_WH    WITH WAREHOUSE_SIZE = 'SMALL'  AUTO_SUSPEND = 30   AUTO_RESUME = TRUE                                  STATEMENT_TIMEOUT_IN_SECONDS = 600;
-- ロールに専用 Warehouse をアサインGRANT USAGE ON WAREHOUSE BATCH_WH TO ROLE DBT_RUNNER;GRANT USAGE ON WAREHOUSE BI_WH    TO ROLE BI_VIEWER;GRANT USAGE ON WAREHOUSE ADHOC_WH TO ROLE ANALYST;

3. クエリ予算アラートの自動化

BigQuery の高コストクエリを毎日 Slack 通知(INFORMATION_SCHEMA)
SQL
-- 過去24時間で 100GB 超のクエリSELECT  user_email,  query,  total_bytes_billed / POW(10, 9) AS gb_billed,  total_slot_ms / 1000 / 60 AS slot_minutes,  creation_timeFROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECTWHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY)  AND total_bytes_billed > 100 * POW(10, 9)ORDER BY total_bytes_billed DESC;
アラートの強さ

強すぎる(毎日 30 件 Slack に流れる)と慣れて見なくなる。「日次 5 件まで」「予算超過時のみ」など 閾値を絞り、月次レビュー会で長期傾向を別途確認するのが運用しやすい。

4. パーティション・クラスタリングを「強制」する

コスト爆発の原因の多くは パーティション忘れ。テーブル設計時に `require_partition_filter = TRUE` を必須化し、`WHERE _PARTITIONTIME` がないクエリを DDL レベルでリジェクトする。

BigQuery で partition filter を必須化
SQL
CREATE OR REPLACE TABLE `proj.dwh.events`PARTITION BY DATE(event_time)CLUSTER BY user_id, event_typeOPTIONS (  require_partition_filter = TRUE,  -- これがあれば WHERE _PARTITIONTIME 必須  partition_expiration_days = 365);

5. 月次のコスト責任配分

民主化が進むと、「誰がいくら使ってるか分からない」状態になる。Slack 通知だけでは責任は固まらない。部署別・チーム別に DWH コストをタグ付け / Reservation 割当て月次のコスト振り分けを可視化する。

DWH部署タグの方法
BigQueryReservation Assignment + ラベル / プロジェクト分離
SnowflakeWarehouse の所有ロール、`QUERY_TAG` 強制
Redshiftユーザグループ + WLM Queue
Snowflake: ロールごとに QUERY_TAG を必須化(運用フック)
SQL
-- セッション開始時に QUERY_TAG が空ならエラー(実装は session policy で)ALTER ROLE BI_USERS SET QUERY_TAG_REQUIRED = TRUE;
-- ユーザは自分のセッションで明示的にタグを設定ALTER SESSION SET QUERY_TAG = 'team:marketing,project:campaign-q4';
-- 月次集計で部署別コストSELECT  PARSE_JSON(query_tag):team::STRING AS team,  SUM(credits_used_cloud_services) AS creditsFROM SNOWFLAKE.ACCOUNT_USAGE.QUERY_HISTORYWHERE start_time >= DATEADD(month, -1, CURRENT_DATE())GROUP BY 1;

6. 「予算」ではなく「予測」で先回り

月初 → 月末で予算消化が線形でないことが多い。中旬時点で「月末超過予測」を計算し、早期に調整する仕組みが効く。

月次予算の消化進捗から月末予測(線形外挿)
Python
from datetime import datetimefrom calendar import monthrange
def project_monthly_spend(spent_to_date: float, today: datetime) -> dict:    days_in_month = monthrange(today.year, today.month)[1]    day_of_month = today.day    daily_avg = spent_to_date / day_of_month    projected = daily_avg * days_in_month    return {        "spent_to_date": spent_to_date,        "daily_avg": daily_avg,        "projected_eom": projected,        "remaining_days": days_in_month - day_of_month,    }
# 例: 15日時点で $750 使ってるprint(project_monthly_spend(750, datetime(2027, 12, 15)))# {'projected_eom': 1500.0, ...}  → 月予算 $1000 なら早めに調整

次の話

EP.07 では、メタデータ基盤。dbt docs / DataHub / Atlan のどれを選ぶか、運用にどう乗せるか。「このテーブル何ですか?」に機械的に答える土台。

シェア

この記事の感想を教えてください

あなたの 1 クリックで、本当にこの記事は更新されます。「もっと詳しく」「続編希望」が一定数集まった記事は、 ふくふくが 実際に内容を拡充したり続編記事を公開 します。 送信したリアクションはお使いのブラウザに記録され、再カウントされません。

シリーズの外も探す:

まずは、現状を聞かせてください。

要件が固まっていなくて大丈夫です。現状診断と方針提案までを無料でお手伝いします。

無料相談フォームへ hello [at] hukuhuku [dot] co [dot] jp