はじめに:毎朝手でクエリを叩くのをやめたい

「毎朝、出社したらまず昨日までの売上集計クエリを実行して、その結果をスプレッドシートに貼る」——中小ECや個人事業の現場でよく見かける光景です。やっていること自体は数分で終わるのですが、毎日続くと地味に手間ですし、何より「忘れる」「人によってやり方が違う」「休んだ日は更新が止まる」といった問題がついて回ります。

この手の「決まったクエリを決まった時間に流す」作業は、BigQuery標準の スケジュールクエリ(Scheduled Queries) で丸ごと自動化できます。追加のサーバーもツールも要りません。BigQueryのコンソールだけで完結します。

この記事では、毎朝決まった時間にデータマート(集計済みテーブル)を作り直す設定の手順と、「ちゃんと動いているか」を見張る監視のやり方までをセットで紹介します。

スケジュールクエリとは(BQ標準機能)

スケジュールクエリは、BigQueryに用意されている「クエリを定期実行するための機能」です。指定したSQLを、指定した間隔(毎日・毎時・毎週など)で自動的に実行してくれます。

ポイントは次のとおりです。

  • 追加の仕組みが不要 — Cloud Schedulerや自前のバッチサーバーを立てる必要がありません。BigQueryの中で完結します。
  • 実行結果をテーブルに保存できるCREATE OR REPLACE TABLE や、宛先テーブルへの追記・上書きに対応しています。
  • 権限はサービスアカウント or 実行ユーザー — 内部的にはBigQuery Data Transfer Serviceの仕組みを使って動きます。

「毎朝の集計を自動化したい」というニーズには、まずこれを検討するのが定石です。

補足:スケジュールクエリは内部的に BigQuery Data Transfer Service を使っています。初めて使うプロジェクトでは、コンソールの案内に従って関連APIの有効化を求められることがあります。

データマートを毎朝 CREATE OR REPLACE する設定

ここでは「日次の売上サマリーテーブルを毎朝6時に作り直す」例で進めます。

1. 集計用のSQLを用意する

まずは元になる集計クエリを書きます。今回は注文テーブル(raw.orders)から、日別の売上・注文件数・客単価をまとめたデータマート(mart.daily_sales)を作る想定です。

スケジュールクエリでは、テーブルそのものを毎回作り直す CREATE OR REPLACE TABLE がシンプルで扱いやすいです。

CREATE OR REPLACE TABLE `myproject.mart.daily_sales` AS
SELECT
  DATE(ordered_at, 'Asia/Tokyo') AS order_date,
  COUNT(DISTINCT order_id)       AS order_count,
  SUM(amount)                    AS sales_total,
  SAFE_DIVIDE(SUM(amount), COUNT(DISTINCT order_id)) AS avg_order_value
FROM `myproject.raw.orders`
WHERE status = 'paid'
  AND DATE(ordered_at, 'Asia/Tokyo') >= DATE_SUB(CURRENT_DATE('Asia/Tokyo'), INTERVAL 90 DAY)
GROUP BY order_date
ORDER BY order_date;

CURRENT_DATE('Asia/Tokyo') のようにタイムゾーンを明示しているのがポイントです(後述の注意点で詳しく触れます)。直近90日だけを作り直すことで、フルスキャンを避けてコストも抑えています。

2. コンソールからスケジュール登録する

SQLができたら、BigQueryコンソールで定期実行を設定します。画面の文言はアップデートで変わることがあるので、細かいラベルは最新の画面に従ってください。おおまかな流れは次のとおりです。

  1. BigQueryのクエリエディタに、上記のSQLを貼り付ける。
  2. エディタ上部の 「スケジュール」(Schedule)ボタンから新規スケジュールを作成する。
  3. スケジュール名を分かりやすく付ける(例:daily_sales_mart)。
  4. 繰り返しの頻度を 「毎日(Daily)」 にし、実行開始時刻を指定する。
  5. タイムゾーンの欄を確認し、想定どおりか確認する(初期値がUTCのことがあります)。
  6. 失敗時の通知(後述)を設定する。
  7. 保存する。

CREATE OR REPLACE TABLE をSQL側に書いている場合は、宛先テーブルの個別指定は不要です。SQLの中で完結するので、スケジュール設定側はシンプルになります。

3. テスト実行で確認する

登録したら、いきなり翌朝を待つのではなく、一度手動で実行して結果を確かめましょう。スケジュール一覧から該当のスケジュールを開き、手動実行(バックフィル/今すぐ実行)を行うと、その場でクエリが走ります。

mart.daily_sales が想定どおり作られているか、件数や日付の範囲をプレビューで確認しておくと安心です。

監視:失敗通知とINFORMATION_SCHEMAでの実行確認

自動化で一番怖いのは「いつの間にか止まっていて、誰も気づかない」ことです。設定とセットで監視も用意しておきます。

失敗通知を有効にする

スケジュールクエリの設定画面には、実行に失敗したときの通知オプションがあります。代表的なのは次の2つです。

  • メール通知 — 設定したユーザーに失敗メールが届きます。まずはこれだけでも有効にしておきましょう。
  • Pub/Sub通知 — 失敗(や完了)をPub/Subトピックに飛ばせます。Slack連携など、より柔軟な通知を組みたい場合に使います。

最初はメール通知で十分です。「届かないこと=正常」になるので、定期的に「ちゃんと通知が来る状態か」を確認しておくと、より安心です。

INFORMATION_SCHEMAで実行履歴を確認する

「本当に毎朝動いているか」「何秒くらいかかっているか」「どれくらいスキャンしているか」は、INFORMATION_SCHEMA.JOBS から確認できます。スケジュールクエリの実行も、ここにジョブとして記録されます。

SELECT
  creation_time,
  job_id,
  state,
  error_result.message       AS error_message,
  total_bytes_processed,
  TIMESTAMP_DIFF(end_time, start_time, SECOND) AS duration_sec
FROM `region-asia-northeast1`.INFORMATION_SCHEMA.JOBS
WHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 3 DAY)
  AND statement_type = 'CREATE_TABLE_AS_SELECT'
  AND destination_table.table_id = 'daily_sales'
ORDER BY creation_time DESC;

region-asia-northeast1 の部分は、データセットのロケーションに合わせて変えてください。error_messageNULLstateDONE になっていれば成功です。total_bytes_processed を見ておくと、スキャン量が急に増えていないか(=コストが膨らんでいないか)にも早めに気づけます。

補足:このクエリ自体をもうひとつのスケジュールクエリとして毎朝走らせ、「直近で失敗があれば結果に残る」ようにしておくと、簡易的なヘルスチェックになります。

注意:タイムゾーン・依存順序・コスト

タイムゾーン:BigQueryのタイムスタンプはUTC基準です。スケジュールの実行時刻も、SQL内の CURRENT_DATE() も、何も指定しないとUTCで動きます。日本時間の「昨日まで」を集計したいのに、UTCのままだと9時間ずれて、当日分が中途半端に混ざることがあります。スケジュール時刻は Asia/Tokyo で設定し、SQL内でも CURRENT_DATE('Asia/Tokyo') のようにタイムゾーンを明示しましょう。

依存順序:「テーブルAを作ってから、それを使ってテーブルBを作る」といった依存関係がある場合、単純に同じ時刻に2本のスケジュールを置くと、Bが古いAを参照してしまう恐れがあります。実行時刻を十分にずらす、1本のクエリにまとめる、あるいは依存関係を扱える仕組み(ワークフロー系のサービス)を検討する、といった対策が必要です。まずは「時刻をずらす」だけでも事故はかなり減ります。

コスト:スケジュールクエリは「毎日自動で走る」ため、1回あたりのスキャン量が積み重なります。CREATE OR REPLACE TABLE で毎回フルスキャンしていると、地味に費用がかさみます。パーティション列での絞り込みや、直近N日だけを作り直す設計でスキャン量を抑えましょう。

まとめ

毎朝の集計クエリは、BigQuery標準のスケジュールクエリで自動化できます。要点を振り返ります。

  • 集計SQLを CREATE OR REPLACE TABLE で書き、コンソールの「スケジュール」から毎日実行に登録する。
  • いきなり本番運用せず、手動実行で結果を確かめてから任せる。
  • 失敗通知(メール/Pub/Sub)と INFORMATION_SCHEMA.JOBS での実行確認をセットで用意し、「止まっていることに気づけない」状態を避ける。
  • タイムゾーン・依存順序・コストの3点には特に注意する。

一度仕組みを作ってしまえば、「毎朝の手作業」は「届かない失敗通知を眺めるだけ」に変わります。手で叩いていた時間を、もっと考えるべきことに使えるようになります。

なお、運用コストを抑える具体的なテクニックは BigQueryの費用を月1万円以下に抑えるための実践テクニック に、集計の高速化については マテリアライズドビューでGA4の集計を速くする にまとめています。あわせてどうぞ。