ホーム / Skills / 開発効率化 / BigQuery 最適化 BigQuery Optimization
開発効率化

BigQuery 最適化 BigQuery Optimization

GoogleApache-2.0Skill の言語: 英語
ライセンス確認済みスクリプトなし外部サービスが必要認証情報が必要
デモ実行記録 · claude-sonnet-5-5 · 2026年10月
Optimize this BigQuery query (project shop-prod, I don't know the region): SELECT * FROM shop.orders WHERE EXTRACT(YEAR FROM order_ts) = 2025 AND customer_id NOT IN (SELECT customer_id FROM shop.blocked) ORDER BY order_ts
Skill: bigquery-optimization
Read: references/sql_optimization.md
Read: references/table_partitioning_clustering.md

Scope: project shop-prod, region us. You didn't give a region, so I assumed us. If shop lives elsewhere, use your region in any INFORMATION_SCHEMA queries (for example region-europe-west1). I haven't run anything against your project. This rewrite comes from the query text alone, and I'm assuming order_ts is a TIMESTAMP.

Optimized query

SELECT
  order_id,        -- replace with the columns you actually need
  customer_id,
  order_ts
FROM
  `shop-prod.shop.orders`
WHERE
  order_ts >= TIMESTAMP '2025-01-01 00:00:00'
  AND order_ts <  TIMESTAMP '2026-01-01 00:00:00'
  AND customer_id NOT IN (
    SELECT customer_id
    FROM `shop-prod.shop.blocked`
    WHERE customer_id IS NOT NULL
  )
ORDER BY
  order_ts
LIMIT 1000;  -- remove or adjust if you really need every row

Summary of optimizations

  1. Replaced EXTRACT(YEAR FROM order_ts) = 2025 with a range filter. A function on the column prevents partition pruning and block pruning. A plain range on order_ts lets BigQuery prune statically.
  2. Added WHERE customer_id IS NOT NULL to the NOT IN subquery. This lets BigQuery use an anti-hash join instead of the slower left outer hash join.
    • Behavior change: if shop.blocked contains a NULL customer_id, the original query returns zero rows, because NOT IN with a NULL evaluates to NULL. The rewrite returns the rows you almost certainly intended. If you somehow relied on the old behavior, tell me.
  3. Replaced SELECT * with an explicit column list. This reads less data. I don't know your schema, so fill in the columns you need.
  4. Added LIMIT to the ORDER BY. A full sort of a year of orders is expensive. If you need all rows, drop the LIMIT, or consider whether the sort is needed at all.

Table layout (biggest lever if the table is large)

The range filter only prunes partitions if shop.orders is partitioned on order_ts. To check, run:

bq show --format=prettyjson shop-prod:shop.orders

Look at timePartitioning, clustering and requirePartitionFilter in the output.

If the table is not partitioned, and each day holds roughly 10 GB or more (otherwise cluster only), you can create a partitioned copy:

CREATE TABLE `shop-prod.shop.orders_partitioned`
  PARTITION BY TIMESTAMP_TRUNC(order_ts, DAY)
  CLUSTER BY customer_id
  OPTIONS (require_partition_filter = TRUE)
AS
SELECT * FROM `shop-prod.shop.orders`;

You can't convert the existing table in place. Note that require_partition_filter = TRUE makes any query without an order_ts filter fail.

Validate before running

A dry run shows the bytes the query would process, and it costs nothing:

bq query --use_legacy_sql=false --dry_run "<the optimized query>"

Run it on the original query and on the rewrite, and compare totalBytesProcessed. The dry run won't show savings from clustering, since those happen at execution time.

These changes should improve cost-efficiency, but I can't promise a particular saving until you've compared the dry-run numbers.

Trial with only the Skill and Read tools: no Google Cloud access, no gcloud or bq. So only the SQL-rewrite path was exercised, from the query text alone; the model proposed the bq show and dry-run commands but did not run them. Capacity, billing and gcloud workflows were read but not tried.

できること
BigQuery を最適化する Google の手順をモデルに渡します。SQL の書き換え、テーブル設計の提案、課金モデルの説明を行い、費用に影響する変更はモデルが実行せず、あなたに任せるよう指示しています。

仕組み

  1. SQL 最適化:具体的なルール集(EXTRACT ではなく範囲条件、NOT IN サブクエリの NULL 除外、ORDER BY には LIMIT、最上位の SELECT * を避ける、結合前の事前集計 など)。最後に変更点の要約を付けます。
  2. テーブル設計:パーティションとクラスタリングの使い分け、DDL テンプレート、未パーティションのテーブルの移行、require_partition_filter。
  3. ストレージと課金:論理ストレージと物理ストレージ、タイムトラベル、パーティションの有効期限、検索インデックス・マテリアライズドビュー・BI Engine を使うべき場面。
  4. 容量:オンデマンドと Editions について Slot Estimator の推奨をどう読むか。コミットメントの購入、予約の変更、課金モデルの変更は Cloud Console でご自身が行います。

向いている場面
高コストなクエリのチューニング、大きなテーブルの設計や修正、BigQuery の請求の見直し。

制限
SQL の書き換えはクエリ文だけで行えます。分析系の作業には Google Cloud SDK とプロジェクトへのアクセスが必要で、ドライランの数値を自分で確認する代わりにはなりません。

補足とリスク

中リスク:スクリプトはありませんが、指示にはエージェントがあなたの Google Cloud プロジェクトに対して `gcloud` と `bq` を実行する内容が含まれます。Google Cloud SDK、ログイン済みのアカウント(またはサービスアカウントの鍵ファイル)、請求先アカウント、IAM ロール(BigQuery 管理者、データ編集者、ジョブユーザーに言及)が必要です。準備手順には、プロジェクト設定を変更する `gcloud config set project` と `gcloud services enable`、関連 Skill のインストールコマンド(`npx skills add ...`)が含まれます。また、この Skill 自身の `gcloud` 呼び出しに利用状況の帰属ラベルを付け、Google に送る User-Agent に Skill 名とバージョンを加えるよう指示しており、無効にするよう頼むこともできます。コミットメントの購入、課金モデルの変更、DDL の実行はエージェント自身では行わず、提案してあなたが実行するよう指示されています。それでも、各コマンドは承認前に必ず確認し、まず本番ではないプロジェクトで試し、クエリやストレージの変更には費用がかかることを忘れないでください。今回の試用では SQL 書き換えの経路だけを使い、クラウドには接続していません。

SKILL.md 原文パッケージ内 11 ファイル