Contents
1. BigQuery スケジュールクエリとは
BigQuery のスケジュールクエリは、SQL を 定期実行 できるネイティブ機能です。バッチコードを書かずに日次集計や月次レポートを自動化でき、ETL ツールの導入コストを削減します。
- 対象 SQL:
SELECTのみならず DDL/DML も含めた任意のクエリが実行可能です。 - 実行頻度:分単位から月単位まで、CRON 形式や「毎日 / 毎週」など柔軟に設定できます。
- 保存先:テーブル(パーティション推奨)や外部ストレージへ直接書き込めます。
ポイント:スケジュールクエリは、データ基盤で頻繁に行う集計・加工タスクを「コードなし」で運用できる最適解です。
2. コンソールからの作成手順
2‑1. 基本フローの概要
Google Cloud コンソールは UI が直感的で、初心者でも設定ミスが起きにくい点が特徴です。以下では 「プロジェクト選択 → SQL 入力 → スケジュール設定」 の流れを示します。
2‑2. プロジェクト選択と SQL 入力
- コンソール左上のプロジェクトドロップダウンで対象プロジェクトを切り替えます。
- BigQuery → クエリを書く をクリックし、標準 SQL エディタを開きます。
サンプルクエリ(日次売上集計)
|
1 2 3 4 5 6 7 8 9 10 |
-- daily_sales_summary.sql INSERT INTO `my_dataset.sales_daily` PARTITION BY DATE(_PARTITIONTIME) SELECT DATE(order_timestamp) AS order_date, SUM(amount) AS total_amount, COUNT(*) AS order_cnt FROM `my_dataset.orders` WHERE _PARTITIONTIME = TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 1 DAY); |
2‑3. スケジュール設定とパラメータ化
| 手順 | 内容 |
|---|---|
| スケジュール実行 | 「スケジュール実行」→「新しいスケジュールクエリを作成」をクリック |
| 頻度・開始日時 | 例:毎日 02:00(Asia/Tokyo)に設定。カレンダーで開始日、タイムゾーンを指定 |
| パラメータ化 | _PARTITIONTIME を利用すれば実行時の日時が自動的に反映されます。必要に応じて @run_time 変数や独自パラメータ(例: @target_date)を parameter_file で渡せます |
| 保存先テーブル | PARTITION BY DATE(_PARTITIONTIME) により日付単位のパーティションが自動作成され、結果は sales_daily$YYYYMMDD に書き込まれます |
結論:コンソールだけで完結できるので、最初の実装は「作成 → テスト実行 → スケジュール保存」の 3 手順に絞れます。
3. bq コマンドラインから定義・実行
3‑1. CLI が向くシナリオ
スクリプト化や CI/CD パイプラインへの組み込みが必要な場合は、bq ツールで同等の設定が可能です。以下では主要フラグとサンプルスクリプトを紹介します。
3‑2. 主なオプションと使い方
| フラグ | 説明 |
|---|---|
--schedule |
CRON 形式(例:0 2 * * *)または「every N minutes」などの頻度指定 |
--destination_table |
結果を書き込むテーブル。パーティション化推奨 |
--parameter_file |
JSON/YAML で外部パラメータを渡す(例: @target_date) |
--time_zone |
実行タイムゾーン(必ず明示して UTC とローカルのずれを防止) |
3‑3. 完全サンプルスクリプト
|
1 2 3 4 5 6 7 8 9 |
# daily_sales_summary.sql は上記と同一 bq query \ --use_legacy_sql=false \ --destination_table=my_dataset.sales_daily$$(date -d 'yesterday' +%Y%m%d) \ --schedule="0 2 * * *" \ --time_zone="Asia/Tokyo" \ --parameter_file=./params.json \ < daily_sales_summary.sql |
params.json(任意使用例)
|
1 2 3 4 5 6 7 |
{ "target_date": { "type": "STRING", "value": "$(date -d 'yesterday' +%Y-%m-%d)" } } |
このコマンドは 毎日 02:00(東京時間)に クエリを実行し、sales_daily_YYYYMMDD の形式でテーブルに追記します。
結論:CLI は UI と同等の柔軟性があり、スクリプト化すれば運用自動化やコードレビューが容易になります。
4. IaC(Infrastructure as Code)による自動管理
4‑1. なぜ IaC が必要か
手作業で作成したスケジュールは 設定ミス・ドリフト の温床です。Terraform や REST API を用いてコード化すれば、バージョン管理・再現性が確保でき、環境間の差異も最小化できます。
4‑2. Terraform での実装例
4‑2‑1. リソース選定のポイント
2024 年時点で スケジュールクエリは Data Transfer Service の scheduled_query データソース として提供されています。したがって、Terraform では google_bigquery_data_transfer_config を利用します。
4‑2‑2. 完全な Terraform 設定
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
terraform { required_providers { google = { source = "hashicorp/google" version = "~> 5.0" } } } provider "google" { project = var.project_id region = var.region # 例: "us-central1" } /* ------------------------------------------------- スケジュールクエリ(Data Transfer Config) ------------------------------------------------- */ resource "google_bigquery_data_transfer_config" "daily_sales_summary" { display_name = "Daily Sales Summary" data_source_id = "scheduled_query" destination_dataset_id = "my_dataset" params = { query = file("${path.module}/sql/daily_sales_summary.sql") writeDisposition = "WRITE_APPEND" destination_table_name_template = "sales_daily_{run_time|"%Y%m%d"}" partitioningField = "_PARTITIONTIME" useLegacySql = false } schedule_options { // CRON 形式で毎日 02:00(Asia/Tokyo)に実行 schedule = "0 2 * * *" time_zone = "Asia/Tokyo" start_time = "2026-06-01T02:00:00Z" // 必要ならリトライ設定も可能 disable_auto_scheduling = false } } |
ポイント解説
| 項目 | 説明 |
|---|---|
data_source_id = "scheduled_query" |
スケジュールクエリは Data Transfer Service の一種として扱われます。 |
destination_table_name_template |
{run_time} 変数で実行時刻をテーブル名に埋め込め、パーティション化と同等の効果があります。 |
schedule_options.schedule |
CRON 形式(分 時 日 月 曜日)で頻度を指定。秒単位はサポートされません。 |
time_zone |
明示的に設定しないと UTC がデフォルトになるため、ローカル時間ずれのリスクがなくなります。 |
注意:
schedule_optionsはベータ機能ではなく GA です(2024 年 5 月時点)。最新情報は公式プロバイダーリファレンスで確認してください。
4‑2‑3. Terraform の運用上のベストプラクティス
- モジュール化
- スケジュールクエリごとに
module "scheduled_query"を作成し、project_id,dataset_id,sql_path,cronだけを変数として渡す。 - 状態管理
- Terraform のバックエンドは Cloud Storage に保存し、チーム全員で共有することで状態ドリフトを防止。
- レビューとテスト
terraform planで差分確認後、ステージング環境にデプロイして実行結果・コストをモニタリング。
4‑3. REST API によるスケジュールクエリ作成
4‑3‑1. エンドポイントの選択基準
projects.locations.jobs→ 単発ジョブ(一回限り)projects.locations.transferConfigs→ 永続的にスケジュールされたクエリ(本番利用向け)
したがって、永続的なスケジュールは Transfer Configs API を使用します。
4‑3‑2. Transfer Config 作成リクエスト例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
curl -X POST \ -H "Authorization: Bearer $(gcloud auth print-access-token)" \ -H "Content-Type: application/json" \ https://bigquerydatatransfer.googleapis.com/v1/projects/${PROJECT_ID}/locations/us/transferConfigs \ -d '{ "displayName": "Daily Sales Summary", "dataSourceId": "scheduled_query", "destinationDatasetId": "my_dataset", "params": { "query": "'"$(cat sql/daily_sales_summary.sql)"'", "writeDisposition": "WRITE_APPEND", "destinationTableNameTemplate": "sales_daily_{run_time|\"%Y%m%d\"}", "partitioningField": "_PARTITIONTIME", "useLegacySql": false }, "scheduleOptions": { "schedule": "0 2 * * *", "timeZone": "Asia/Tokyo", "startTime": "2026-06-01T02:00:00Z" } }' |
重要ポイント
| 項目 | 説明 |
|---|---|
dataSourceId = "scheduled_query" |
スケジュールクエリ用の固定値 |
destinationTableNameTemplate |
{run_time} により実行日時をテーブル名に埋め込む(パーティション代替) |
scheduleOptions.schedule |
CRON 形式で頻度指定。秒単位は不可です。 |
エンドポイント transferConfigs.create → 永続的スケジュールが作成され、以後自動実行されます。 |
4‑3‑3. REST API 利用時の注意点
- 認証トークンの有効期限
gcloud auth print-access-tokenは 1 時間で失効します。CI/CD ではサービスアカウントキーを利用し、gcloud auth activate-service-accountまたは直接 JWT を生成してください。- リクエストサイズ制限
queryフィールドは最大 256 KB。長いスクリプトは Cloud Storage に保存し、queryFileUriパラメータで参照できます(2024 年追加機能)。- エラー処理
- 400 系エラーはパラメータ不備、403 は権限不足、409 は同名の Config が既に存在。レスポンスボディをログに残すとトラブルシュートが楽になります。
結論:Terraform が利用できる環境ではコード化が最も安全で管理しやすく、REST API はスクリプト単体や緊急対応・外部システム連携の際に有用です。
5. 運用・最適化ガイド
5‑1. IAM の最小権限設計
| ロール | 主な権限 | 推奨使用ケース |
|---|---|---|
roles/bigquery.jobUser |
bigquery.jobs.create、bigquery.jobs.get |
本番スケジュールクエリ用サービスアカウントに付与(ジョブ作成のみ) |
roles/bigquery.dataEditor (データセット限定) |
テーブル書き込み権限 (bigquery.tables.updateData) |
パーティションテーブルへの書き込みだけが必要な場合 |
roles/bigquery.admin |
全権限 | 開発・検証環境でのフルアクセス(本番では避ける) |
ポイント:本番は「jobUser + データセット単位の dataEditor」で最小権限を実現し、誤操作リスクを低減します。
5‑2. 実行結果のモニタリングと通知
- ジョブ履歴確認
-
コンソール > BigQuery > ジョブ一覧でステータス・エラーメッセージが閲覧可能。失敗時は「詳細」から SQL エラーや権限不足を特定できます。
-
Cloud Monitoring ダッシュボード
bigquery.googleapis.com/query/slot_secondsやbigquery.googleapis.com/job/countでスロット使用量・ジョブ回数を可視化。-
カスタムメトリクスで「失敗ジョブ数」アラートを作成し、Pub/Sub → Cloud Functions で自動再実行や Slack 通知へ連携可能です。
-
コスト管理
bigquery.googleapis.com/query/bytes_processedをモニタリングし、急激なスキャン量増加を検知。- パーティションプルーニングが正しく機能しているかは「スキャンバイト」列で確認できます。
5‑3. パラメータファイルと CRON 設定のベストプラクティス
5‑3‑1. パラメータファイル(JSON)例
|
1 2 3 4 5 6 7 8 9 10 11 |
{ "run_time": { "type": "STRING", "value": "{{ run_time }}" // Terraform の templatefile で動的置換可 }, "target_date": { "type": "STRING", "value": "$(date -d 'yesterday' +%Y-%m-%d)" } } |
run_timeは BigQuery が自動提供する変数(ISO8601)で、テーブル名テンプレートやクエリ内部のフィルタに利用できます。parameter_fileを使用すると SQL 内で@target_dateのように参照でき、スクリプトを汎用化できます。
5‑3‑2. CRON 表記のポイント
| フィールド | 記号例 | 説明 |
|---|---|---|
| 分 | 0-59 |
*/15 → 15分ごと |
| 時間 | 0-23 |
2 → 午前2時 |
| 日 | 1-31 |
* → 毎日 |
| 月 | 1-12 |
1,7 → 1月と7月 |
| 曜日 | 0-6 (Sun=0) |
MON-FRI → 平日のみ |
例:毎週月曜・水曜・金曜の 03:30 に実行 →
"30 3 * * MON,WED,FRI"
5‑4. よくある落とし穴と対策
| 落とし穴 | 原因 | 推奨対策 |
|---|---|---|
| タイムゾーンずれ | time_zone 未指定、または UI と API が異なるデフォルト |
常に Asia/Tokyo など明示的に設定 |
| 月末処理が月の最終日で失敗 | 固定日付 (31) を使用したため、2/28 でエラー |
_PARTITIONTIME = TIMESTAMP_TRUNC(DATE_SUB(CURRENT_DATE(), INTERVAL 1 DAY), MONTH) のように相対式を使う |
| クエリ失敗時の自動リトライが無い | スケジュールクエリはデフォルトで 1 回だけ実行 | Cloud Scheduler + Pub/Sub → Cloud Functions で retry_config を設定し、再実行ロジックを追加 |
6. まとめ
- BigQuery のスケジュールクエリ は UI・CLI・IaC のいずれでも簡単に導入でき、ETL コストを大幅削減します。
- Terraform →
google_bigquery_data_transfer_configを使うのが公式かつ推奨される方法です。 - REST API は
transferConfigs.createエンドポイントで永続的スケジュールを作成し、緊急対応や外部システム連携に活用します。 - 運用面 では IAM の最小権限設定、モニタリング・通知の自動化、パラメータファイルと CRON の正確な記述が成功の鍵です。
最終的なアクション:まずはコンソールで「日次集計」スケジュールを作成し、動作確認後に Terraform へコード化する流れをおすすめします。これにより手順の自動化と再利用性が同時に実現できます。