mcpField
B
bigquery

bigquery

github.com/lanejデータ・データベース4161 回インストール今日更新
リポジトリ

bigquery について

BigQueryを扱う開発者やエージェント向けのCLI・MCPガイドです。クエリやデータセット、テーブルの管理に加え、自動ドライランと費用確認でクエリコストを把握できます。

主な機能

  1. 01CLIでクエリ、データセット、テーブル、ジョブを管理
  2. 02クエリを自動ドライランして費用を確認
  3. 03JSON、テキスト、JSONL形式に対応
  4. 04読み取り専用MCPツールと任意の書き込みツール
  5. 05テーブルのスキーマとメタデータをリソースとして公開

活用シーン

  1. 01スキャン量を確認してSQLを実行
  2. 02CLIまたはMCPでデータセットやテーブルを探索
  3. 03BigQueryへデータを挿入または一括ロード

MCP 対応

BigQuery MCPサーバーは、クエリ、費用見積もり、データセットやテーブルの検出、テーブル記述のツールを提供し、スキーマとメタデータもリソースとして公開します。既定は読み取り専用で、`--enable-writes` により書き込みツールを有効化できます。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/lanej/dotfiles --skill bigquery

インストール後、Claude Code で/bigqueryを入力して読み込まれたか確認します。

詳細

BigQuery CLI と MCP サーバー

CLI と MCP の比較

CLI は完全なインターフェースです。MCP ツールはその一部です。

以下の MCP ツールのセクションに記載されていない操作には、デフォルトで bigquery CLI を使用してください。エージェントが構造化されたツール呼び出しのセマンティクスを必要とする場合は、MCP を使用してください。

認証

Google Cloud SDK(gcloud)の ADC を使用します。BigQuery 専用の認証は不要です。

bigquery auth check   # verify status and scopes

出力形式のデフォルト

コマンドデフォルト備考
queryJSONメタデータ(bytes、cost、cacheHit)を含みます
datasets listテキスト人が読みやすい形式です
tables listテキスト人が読みやすい形式です

すべてのコマンドで --format json|text|jsonl を指定できます。

クエリ操作

# Basic (automatic dry-run + cost confirmation)
bigquery query "SELECT * FROM dataset.table LIMIT 10"

# Skip cost confirmation (required for automation)
bigquery query --yes "SELECT COUNT(*) FROM dataset.table"

# JSONL output (one object per line — for pipelines/DuckDB)
bigquery query --jsonl "SELECT * FROM dataset.table"

# Stream large results
bigquery query "SELECT * FROM large_table" --stream > results.jsonl

# From file / stdin
bigquery query --file query.sql
cat query.sql | bigquery query --stdin --yes

# Dry run (cost estimate, $0 to run)
bigquery dry-run "SELECT * FROM large_table WHERE date >= '2025-01-01'"

コストへの配慮:各クエリの前に自動でドライランを実行し、コストがしきい値(デフォルト:1 GB)を超える場合は確認を求めます。応答には bytesProcessed、estimatedCostUSD、cacheHit が含まれます。

主なフラグ:--yes、--format、--jsonl、--stream、--cost-threshold、--max-results、--project

重要:--max-results が制限するのは返される行数であり、スキャンされるバイト数ではありません(コストは削減されません)。代わりに SQL で LIMIT を使用してください。

データセット操作

bigquery datasets list [--project PROJECT]
bigquery datasets describe PROJECT.DATASET
bigquery datasets create PROJECT.DATASET [--description "..." --location US --default-ttl 30]
bigquery datasets update PROJECT.DATASET --description "..."
bigquery datasets delete PROJECT.DATASET [--force --yes]

テーブル操作

# Read
bigquery tables list PROJECT.DATASET [--max-results 20]
bigquery tables describe PROJECT.DATASET.TABLE

# Write
bigquery tables create TABLE --schema '[{"name":"id","type":"STRING"}]'
bigquery tables update TABLE --description "..."

# Insert (streaming, <1000 rows)
bigquery tables insert TABLE file.jsonl --format jsonl
cat data.jsonl | bigquery tables insert TABLE - --format jsonl

# Load (bulk, >10MB — from Cloud Storage)
bigquery tables load TABLE gs://bucket/data.csv --format csv --write-disposition WRITE_TRUNCATE

# Copy / extract / delete
bigquery tables copy SOURCE DEST [--write-disposition WRITE_TRUNCATE]
bigquery tables extract TABLE gs://bucket/output.csv --format csv
bigquery tables delete TABLE

tables load の注意点:--yes は受け付けません。また、--write-disposition には大文字を指定する必要があります(append ではなく WRITE_APPEND)。

ジョブ管理

bigquery jobs list [--state-filter running|done --all-users]
bigquery jobs get JOB_ID
bigquery jobs cancel JOB_ID

Python のサブプロセスパターン

# query via stdin
result = subprocess.run(
    ["bigquery", "query", "--format", "jsonl", "--yes", "--stdin"],
    input=sql, capture_output=True, text=True, check=True
)

# bulk load (no --yes for tables load)
subprocess.run(
    ["bigquery", "tables", "load", "--format", "json",
     "--write-disposition", "WRITE_APPEND", table, tmpfile],
    check=True
)

MCP サーバー

起動
bigquery mcp stdio                 # read-only (default)
bigquery mcp stdio --enable-writes # with write tools
bigquery mcp http --port 3000      # HTTP mode
MCP ツール(デフォルトでは読み取り専用)

Claude Code では、完全な識別子は mcp__bigquery__* です。

読み取りツール(常に利用可能):

ツール説明
query自動ドライランとコストガード付きで SQL を実行します
dry_run実行せずにコストを見積もります($0)
list_datasetsデータセットを一覧表示します。bigquery://project.dataset URI を返します
list_tablesテーブルを一覧表示します。bigquery://project.dataset.table URI を返します
describe_table完全なスキーマ、行数、メタデータを返します

書き込みツール(--enable-writes が必要):

ツール説明
create_dataset新しいデータセットを作成します
create_tableスキーマ、パーティショニング、クラスタリングを指定してテーブルを作成します
insert_rowsストリーミング挿入(1000 行未満)
load_dataGCS URI から読み込みます(バルク)
execute_ddlDDL/DML(CREATE、INSERT、UPDATE など)を実行します
MCP リソース

テーブルは bigquery://{project.dataset.table} を介してリソースとして公開されます。リソースを取得すると、ツール呼び出し枠を消費することなく、describe_table と同じ出力(スキーマ、行数、メタデータ)が返されます。

bigquery://easypost-platform.DORA.ai_attribution
ワークフロー(MCP)
  1. list_datasets → データセットを検出します(URI の一覧を返します)
  2. list_tables → テーブルを調べます(URI の一覧を返します)
  3. リソース bigquery://project.dataset.table を読み取る → スキーマを取得します
  4. dry_run → コストを見積もります
  5. query → クエリを実行します
MCP 設定
{
  "mcpServers": {
    "bigquery": {
      "command": "bigquery",
      "args": ["mcp", "stdio"]
    }
  }
}

追記専用の raw テーブルパターン

  • table_raw — 追記専用の書き込み先。インプレースで UPDATE/DELETE しないでください
  • table(VIEW)— 読み取り用のビュー。ROW_NUMBER() OVER (PARTITION BY <key> ORDER BY loaded_at DESC) = 1 を使用して重複を排除します
  • 常に loaded_at TIMESTAMP REQUIRED を含め、書き込み時に CURRENT_TIMESTAMP() を設定してください
  • レコードを「更新」するには、修正した値と新しい loaded_at を設定した行を INSERT してください
  • DML の対象に VIEW を指定しないでください。必ず raw テーブルに書き込んでください

データの書き込み — 挿入と読み込みのパターン

A:tables load はローカルファイルのパスを無視します

bigquery tables load には Cloud Storage URI(gs://...)が必要です。ローカルパスを渡すと、終了コード 0 で何も出力されません。テーブルには書き込まれず、後続の読み取り結果は 0 行になります。ローカルファイルには tables insert を使用してください。

B:ストリーミング挿入コマンド
bigquery tables insert --format jsonl --yes <project.dataset.table> <local-file.jsonl>

bigquery insert(tables なし)は存在せず、「unknown command」が返されます。ファイルは JSONL 形式である必要があります。--yes を指定すると、コスト確認のプロンプトをスキップします。

C:新しいテーブルの反映遅延

bigquery tables create の後、メタデータの反映には最大で約 50 秒かかります。直後に tables insert を呼び出すと、「Not found: Table」エラーが返されます。挿入処理をリトライループで囲んでください。

for attempt in range(10):
    result = subprocess.run([...tables insert...], capture_output=True, text=True)
    if result.returncode == 0:
        break
    if "Not found" in result.stderr:
        time.sleep(5)
        continue
    raise RuntimeError(result.stderr)
else:
    raise RuntimeError("table not available after 50s")
D:ストリーミングバッファにより、DELETE/TRUNCATE が約90分間ブロックされます

ストリーミング挿入後に DELETE FROM table WHERE TRUE および TRUNCATE TABLE を実行すると失敗します。

UPDATE or DELETE statement over table would affect rows in the streaming buffer, which is not supported

この状態は最大90分間続きます。WRITE_TRUNCATE のセマンティクス(実行のたびにすべての行を置き換える)にするには、削除して再作成します。

subprocess.run(["bigquery", "tables", "delete", table], capture_output=True)
_ensure_table(table)  # recreate with schema
# propagation delay applies after recreate — use retry loop from (C)

既知の注意点

JSONL 出力の DATE 列は、文字列ではなく {"value": "YYYY-MM-DD"} の辞書を返します。TIMESTAMP 列は ISO 形式の文字列ではなく、エポック秒を表す浮動小数点数の文字列("1.760730316667E9")を返します。

def _parse_date(v) -> str:
    if isinstance(v, dict): return str(v["value"])[:10]
    return str(v)[:10]

def _parse_ts(v) -> datetime:
    try: return datetime.fromisoformat(str(v))
    except ValueError: return datetime.fromtimestamp(float(v), tz=timezone.utc)

数値列は文字列として渡されます。 集計する前にキャストしてください。

df["col"] = pd.to_numeric(df["col"], errors="coerce").fillna(0).astype("int64")

carrier_accounts の結合による行の増幅:ep-core-data.raw.carrier_accounts には重複した ID が約77K件あります。結合する前に、必ず SELECT DISTINCT id, ... で重複を排除してください。検証方法:結合後の COUNT() ≈ 結合前の COUNT()。

CTE/列エイリアスの衝突:CTE と列エイリアスが同じ名前の場合、BQ は ORDER BY col を CTE(STRUCT)として解決し、「Ordering by expressions of type STRUCT is not allowed」が発生します。列エイリアスの名前を変更してください。

ディメンション参照を事前に解決する:shipments(4.2TB)は user_id でクラスタ化されていません。SF アカウントで絞り込むために dim.users と結合すると、日付パーティション全体(77GB 以上)がスキャンされます。代わりに、まず低コストのクエリでディメンション ID を解決し、その後、ファクトテーブルで IN 句を使います。結合は不要です。

Salesforce の created_date は、Polytomic の同期タイムスタンプ(2025年2月以降)であり、SF での作成日ではありません。過去のクエリには close_date または SF 固有の日付フィールドを使用してください。

salesforce.tasks.created_date は INT64 のナノ秒です。TIMESTAMP_MILLIS(CAST(created_date / 1000000 AS INT64)) で変換してください。

UNNEST のリテラルサイズ制限:SQL 文字列内のリテラル配列として UNNEST([key1, key2, ...]) を使い、大量のキー(例:50k 件以上)を渡す SQL クエリを作成すると、bigquery CLI のサブプロセスが「Expecting ',' delimiter: line 1 column 1517」のような JSON 解析エラーで失敗します。SQL 自体は構文的に正しくても、CLI が入出力制限に達する可能性があります。

対処法:大量のキーセットを SQL リテラルに埋め込まないでください。代わりに、対象テーブルからすべての行を取得し(可能であれば REGEXP_CONTAINS などで事前に絞り込み)、Python 側でキーを照合します。これは extract_phab.py の _build_revision_lookup で使われている方法と同じです。すべてのリビジョンを取得し、Python でチケット参照を解析して、対象キーセットとの積集合を取ります。

クイックリファレンス

bigquery auth check
bigquery query --yes "SELECT ..."
bigquery dry-run "SELECT ..."
bigquery datasets list
bigquery tables list PROJECT.DATASET
bigquery tables describe TABLE
bigquery tables insert TABLE file.jsonl --format jsonl
bigquery tables load TABLE gs://bucket/file.csv --write-disposition WRITE_TRUNCATE
bigquery mcp stdio

コメント