BigQueryパーティションとクラスタリングの設計|スキャン量を9割減らす型と設計ミス【2026年版】

データ基盤
読了時間 約10分
BigQueryパーティションとクラスタリングの設計|スキャン量を9割減らす型と設計ミス【2026年版】

「BigQueryの請求書がまた跳ねた。パーティションを切ったはずなのに、なぜ効いていないのか」。そんな相談を月に何件かいただきます。

パーティションとクラスタリングは、公式ドキュメントを読めば設定手順そのものはすぐに分かります。難しいのは、どの列をパーティションにするか、クラスタリング列に何を選ぶか、なぜプルーニングが効かないのか、といった設計判断のほうです。しかもパーティション設計は後から変えるコストが大きく、最初の判断がテーブル全体のコストを決めてしまう構造になっています。

そこで本記事では、パーティションとクラスタリングを「設計の型」として使えるように、選び方の判断軸と現場で踏みがちな落とし穴を整理しました。BigQuery全体の料金体系や日常SQLの課金トラップはBigQueryの料金体系とコスト削減7手|課金トラップと最大30%減の実践策で扱っているので、こちらはテーブル設計そのものに軸足を置いています。


パーティションとクラスタリングが「請求書ショック」に直結する理由

パーティションとクラスタリングが請求書ショックに直結する理由

BigQueryのオンデマンド料金は1TiBあたり$6.25(2026年9月時点、月1TiBまでは無料)です。ここで課金対象になるのは結果として返る行数ではなく、クエリがスキャンしたカラムのデータ量です。

例えば1TBのイベントログテーブルに対して、パーティションなしで SELECT user_id FROM events WHERE event_date = '2026-09-01' を実行すると、WHERE句で1日分しか返らなくても1TB分のフルスキャンになり、1回で約$6.25の料金が発生します。

このテーブルをBIダッシュボードが5分ごとに叩いていたら、1日288回×$6.25 = 1日あたり約$1,800の請求が積み上がる計算です。1分ごとにポーリングするタイプの監視画面なら1日あたり$9,000規模になり、実際、この規模で月次の請求書を見て慌てて連絡をいただく現場は珍しくありません。

同じテーブルを event_date でパーティション分割し、user_id でクラスタリングしておくと、同じクエリのスキャン量は1日分(数GB)に、さらに関連ブロックだけに絞られて数MB〜数百MBまで落ちます。公開されている事例では、日次$175のダッシュボードを日次$1まで下げた例(月次で約$5,000削減)や、5.2GBスキャンを14MBまで、数百倍のスキャン削減を達成した例も報告されています。

つまり、パーティションとクラスタリングは「性能を上げる仕組み」というより、「スキャン量を桁で減らす請求書対策」として理解しておくのが実態に合っています。


パーティション分割の3種類と選び方

パーティション分割の3種類と選び方

BigQueryが公式にサポートするパーティションは、次の3種類です。

種類分割キー主な用途
時間単位列パーティションDATE / TIMESTAMP / DATETIME 型の列イベント時刻を持つログ、トランザクション、業務系テーブル
取り込み時間パーティション自動付与される _PARTITIONTIMEストリーミング取り込み、CDC、時刻列がない生データ
整数範囲パーティションRANGE_BUCKET で区切った整数列customer_id や shop_id で均等分割したいマスタ系

粒度は時単位・日単位・月単位・年単位から選べます。1テーブルあたりのパーティション上限は10,000(2024年に4,000から緩和)で、時間単位パーティションで約1年強、日単位で27年、月単位で833年まで持てる計算になります。

選び方の判断軸

多くの実務ケースで最初の選択肢になるのは、時間単位列パーティション(日単位)です。ログや売上明細のようにイベント時刻がある行データは、ほぼこの型に収まります。

時刻列がなく、後工程のETLで取り込みタイミングだけが分かるデータは、取り込み時間パーティションが向いています。GAやCDCで流し込む生テーブルなどが該当します。

整数範囲パーティションは限定的ですが、顧客IDや店舗IDで論理的に分ける必要があり、かつテーブル自体がそこまで大きくないケースで使います。ただし、後述のクラスタリングで代替できることも多いので、まずは時間パーティション+クラスタリングを検討するのが定石です。

粒度の選び方(細かければよいわけではない)

1パーティションあたりのデータ量は、1GB以上を目安にします。粒度を細かくしすぎるとパーティションあたりのメタデータ管理コストが増え、10,000パーティションの上限にも早く到達します。

例えば1日あたり100MBしかログが発生しないテーブルを日単位で切ると、パーティションがスカスカになりオーバーヘッドが増えます。この場合は月単位パーティション+クラスタリングに切り替えるほうが効率的です。


クラスタリングの仕組みとパーティションとの組み合わせ方

クラスタリングの仕組みとパーティションとの組み合わせ方

クラスタリングは、指定した列でストレージ内のブロックを物理的にソートし、クエリのフィルタ条件と一致しないブロックをメタデータでスキップする仕組みです。最大4列まで指定でき、指定した順序が意味を持ちます。

パーティションが「棚で分ける」だとすれば、クラスタリングは「棚の中を並べ替える」に近い挙動です。パーティションはドライラン時点でスキャン量が事前に確定するのに対して、クラスタリングは実行するまで実際の削減量が確定しないという違いもあります。

組み合わせの定石

現場で最も効くのは、PARTITION BY で粗く区切り、CLUSTER BY で細く絞る組み合わせです。適切に組み合わさったクエリでは、スキャン量が90〜99%削減されるケースも珍しくありません。

CREATE TABLE analytics.events (
  event_id STRING,
  event_ts TIMESTAMP,
  user_id  STRING,
  country  STRING,
  payload  JSON
)
PARTITION BY DATE(event_ts)
CLUSTER BY user_id, country
OPTIONS (
  partition_expiration_days = 400,
  require_partition_filter  = TRUE
);

このテーブルに対して WHERE event_ts >= '2026-09-01' AND event_ts < '2026-09-02' AND user_id = 'u_12345' のように書けば、まず9月1日のパーティションだけに絞られ、その中で user_id = 'u_12345' を含むブロックだけがスキャンされます。

クラスタリング列の選び方

カーディナリティが高い列を選ぶのが基本です。user_id・product_sku・region のように、値のバリエーションが多く、頻繁にWHERE句で使われる列が向いています。

反対にbool型や YES/NO のような低カーディナリティ列を選んでも、ブロックがほぼ全部残ってしまいプルーニングが効きません。指定できるのは4列までなので、「よくフィルタする順に左から並べる」判断がそのままコスト削減に直結します。


現場でよくある設計ミス5つ

現場でよくある設計ミス5つ

パーティションとクラスタリングを設定しても、次の5つのパターンで期待した削減が得られない現場が多くあります。

ミス1: パーティション列に関数を適用

-- ❌ 関数適用でプルーニングが無効になる
SELECT * FROM events WHERE DATE(event_ts) = '2026-09-01';

-- ✅ 静的な範囲比較で書く
SELECT * FROM events
WHERE event_ts >= '2026-09-01' AND event_ts < '2026-09-02';

パーティション列に DATE() や TIMESTAMP_ADD() などの関数を適用すると、BigQueryはどのパーティションに絞れるかを事前判定できず、フルスキャンに戻ってしまいます。

ミス2: サブクエリや動的値でのフィルタ

-- ❌ サブクエリの結果が事前確定しない
SELECT * FROM events WHERE event_ts = (SELECT MAX(event_ts) FROM events);

-- ✅ 一度別のクエリで値を取り、静的な定数で絞る
SELECT * FROM events
WHERE event_ts >= '2026-09-04 00:00:00' AND event_ts < '2026-09-05 00:00:00';

サブクエリや CURRENT_TIMESTAMP() などの動的値で絞ると、ドライランでスキャン量が判定できず、フルスキャン扱いになる場合があります。定期実行のジョブでは、静的な範囲を事前に組み立てて渡す設計が安全です。

ミス3: パーティション粒度の切りすぎ

1パーティションあたり数十MBしかないような粒度でパーティションを切ると、メタデータのオーバーヘッドが増え、10,000パーティション上限にも早く到達します。データ量に合わせて日次から月次に粒度を上げ、クラスタリングで細かい絞り込みを担わせるほうが効率的です。

ミス4: require_partition_filterを付けずBIから素通し

パーティションを切ってもWHERE句に条件を入れる責任は書き手側にあります。BIツールから接続してきた分析ユーザーがWHERE句を省略すれば、そのままフルスキャンです。後述する require_partition_filter を有効にして、書き忘れを機械的に止める設計が現実的です。

ミス5: クラスタリング列に低カーディナリティ列を選ぶ

is_active や status のような値のバリエーションが少ない列をクラスタリング列に指定しても、ほとんどのブロックがフィルタを満たしてしまい、スキャン削減効果がほぼ出ません。カーディナリティが数百以上ある列を優先し、迷ったら実際のフィルタ回数の多い順に選びます。


既存テーブルに後付けする手順(dbtも含む)

既存テーブルに後付けする手順

「今動いているテーブルにパーティションが入っていない」というケースは、実務では非常によくあります。ここで問題になるのは、パーティション設計は後付けできないという制約です。

素のBigQueryでの再作成

パーティションを追加するには、テーブルを作り直す必要があります。

-- 1. パーティション付きの新テーブルを作成
CREATE TABLE analytics.events_new
PARTITION BY DATE(event_ts)
CLUSTER BY user_id
OPTIONS (require_partition_filter = TRUE)
AS
SELECT * FROM analytics.events;

-- 2. 旧テーブルを退避 & リネームで置き換え
ALTER TABLE analytics.events RENAME TO events_old;
ALTER TABLE analytics.events_new RENAME TO events;

-- 3. 動作確認後、旧テーブルを削除
DROP TABLE analytics.events_old;

数百GB以上のテーブルでは、CREATE TABLE AS SELECT の実行に数時間かかります。切り替え中はテーブルへの書き込みを止めるか、更新差分を後追いする段取りを合わせて設計しておきます。

一方、クラスタリングは ALTER TABLE ... SET OPTIONS や ALTER TABLE ... CLUSTER BY で後付けできます。ただし既存データは自動で再クラスタリングされないため、UPDATE を打つか全量を書き換えて初めて既存ブロックにも効くようになります。

dbtでの宣言方法

dbtで管理しているモデルなら、config() にパーティションとクラスタリングを宣言するのが標準です。

{{ config(
    materialized='incremental',
    partition_by={
      'field': 'event_ts',
      'data_type': 'timestamp',
      'granularity': 'day'
    },
    cluster_by=['user_id', 'country'],
    require_partition_filter=true
) }}

初回の切り替え時は dbt run --full-refresh でテーブルを作り直します。dbtコミュニティの公開事例では、パーティションとクラスタリングを組み込んだリファクタリングで月次$20,000規模のコスト削減や、日次バッチが6時間から25分に短縮といった数値が報告されています。dbtで扱う場合は、テーブルオーナー判定を含めた再作成手順を事前に確認しておきます。

このあたりの dbt 側の設計思想はdbtとは?データ変換を効率化するツールと使い方を解説でも触れています。


設計を守るためのガードレール(require_partition_filterと監視)

設計を守るためのガードレール

パーティションとクラスタリングを設計しても、書き手のSQLが崩れると効果が消えます。運用フェーズで安定させるには、次の2つのガードレールを組み合わせるのが定石です。

require_partition_filterで書き忘れを止める

テーブルに require_partition_filter = TRUE を付けると、WHERE句にパーティション列の条件がないクエリは実行前にエラーで拒否されます。

Cannot query over table 'analytics.events' without a filter over
column(s) 'event_ts' that can be used for partition elimination

BIツールやアドホック分析からの誤爆を強制的に止める効果があり、コスト事故が起きた組織ではまず全テーブルに付ける判断をしても構いません。既存のダッシュボードやSQLに影響が出るため、開発環境で INFORMATION_SCHEMA.JOBS_BY_PROJECT を使って影響範囲を洗い出してから、本番に反映します。

INFORMATION_SCHEMA.JOBSでスキャン量を可視化

INFORMATION_SCHEMA.JOBS を集計すれば、ユーザー別・クエリテンプレート別に「どのクエリが何TBスキャンしているか」が見えます。

SELECT
  user_email,
  query,
  ROUND(SUM(total_bytes_billed) / POW(1024, 4), 2) AS scanned_tib,
  ROUND(SUM(total_bytes_billed) / POW(1024, 4) * 6.25, 2) AS estimated_usd
FROM `region-us`.INFORMATION_SCHEMA.JOBS_BY_PROJECT
WHERE creation_time >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
  AND statement_type = 'SELECT'
GROUP BY user_email, query
ORDER BY scanned_tib DESC
LIMIT 20;

このクエリを週次で流して上位10件を確認するだけで、パーティション未使用のフルスキャンや、想定外に重いクエリを早期に検出できます。「請求書ショックの前に検知する」運用の入口として実装コストが低いので、最初に組み込んでおきたい仕組みです。

2026年時点のEditions前提での考え方

現在、多くの現場はスロット課金のBigQuery Editions(Standard / Enterprise / Enterprise Plus)に移行しています。Editionsではクエリ単位のTB課金ではなくスロット時間課金になるため、「同じ月$3,000でも、パーティション設計次第で処理できるクエリ本数が10倍以上変わる」構造になります。

つまり、Editions化してもテーブル設計の重要性は下がるどころか、投資対効果はむしろ上がっています。オートスケール前提の運用でも、粗くパーティションを切っておく設計はコスト予測の安定にも効きます。


まとめ|設計の型を先に決めておく

パーティションとクラスタリングは、後から変えるコストが高い設計判断です。運用の途中で気付くと、CREATE TABLE AS SELECTでの作り直しと切り替え作業が発生し、対象テーブルが大きいほど工数が跳ねます。

現場で最も効くのは、次の順で「設計の型」を先に決めておくことです。

  • 時間単位列パーティション(日単位が基本、少量データは月単位) をまず選ぶ
  • カーディナリティの高い列をクラスタリング列に4個まで、フィルタ頻度順に並べる
  • 新規テーブルには require_partition_filter = TRUE を最初から付ける
  • INFORMATION_SCHEMA.JOBS を週次で見て、フルスキャンの兆候を早期検知する
  • dbtで管理しているモデルは config() に宣言し、--full-refresh の運用手順を決めておく

Evastでは、BigQuery導入初期から Editions 前提のコスト設計・パーティション/クラスタリング設計・INFORMATION_SCHEMA監視の仕組み化まで、データ基盤構築の伴走支援としてご支援しています。既存の請求書ショックに対する原因調査からのご相談も歓迎です。

もし「これから BigQuery を導入する」段階の方は、料金体系や無料枠を含む全体像をBigQuery導入ガイド|手順・料金・無料枠・費用相場【2026年版】で先に押さえておくと、この記事の設計判断がそのまま初期設計に活かせます。

よくある質問

BigQueryのパーティションとクラスタリングは何が違いますか?
パーティションは指定した列(多くは日付やタイムスタンプ)でテーブルを物理的に区切る仕組みで、WHERE句にその列の条件があれば該当パーティションだけがスキャンされます。クラスタリングは指定した最大4列でストレージブロックをソートし、フィルタと一致しないブロックをメタデータでスキップします。パーティションが「棚で分ける」なら、クラスタリングは「棚の中を並べ替える」イメージで、両方を組み合わせるとスキャン量を90〜99%削減できます。
既存テーブルにパーティションは後から追加できますか?
パーティション設計は後付けできません。既存テーブルにPARTITION BYを追加するには、CREATE TABLE new_table AS SELECT * FROM old_table でパーティション付きの新テーブルを作り直し、リネームで置き換える必要があります。数百GB以上のテーブルでは数時間のジョブとダウンタイムを見込みます。クラスタリングはALTER TABLEで後付けできますが、既存データは自動で再クラスタリングされないため全量書き換えが必要です。
クラスタリング列は何個まで、どんな列を選べばよいですか?
最大4列まで指定できます。順序が意味を持ち、先頭列から順に評価されるため、頻繁にWHERE句で使う列を左から並べます。user_idやproduct_skuなどカーディナリティの高い列が効きます。bool型やYES/NOのような低カーディナリティ列を選ぶとブロックのプルーニングがほとんど効かず、無駄になります。
require_partition_filterを付けるとエラーになりませんか?
WHERE句にパーティション列の条件がないクエリはエラーで拒否されます。これがまさに狙いで、BIツールからのフルスキャンやアドホック分析での事故を強制的に防げます。既存のダッシュボードやSQLに影響が出るため、まず開発環境で一括検知してから本番に反映するのが安全です。
パーティションは細かく切ったほうがスキャン量が減りますか?
細かく切りすぎると逆効果です。BigQueryは1テーブルあたり10,000パーティションが上限で、超えるとテーブル作成に失敗します。時間単位パーティションで1年強、日単位で27年、月単位で833年まで持てる計算です。目安は1パーティションあたり1GB以上のデータ量を確保することで、それより小さいとメタデータ管理のオーバーヘッドと10,000上限リスクのほうが大きくなります。
Share:
Back to Blog
Amazon RedshiftからBigQueryへの移行判断と手順|費用相場とSQL方言差【2026年版】 データ基盤
約9分

Amazon RedshiftからBigQueryへの移行判断と手順|費用相場とSQL方言差【2026年版】

Amazon RedshiftからBigQueryへの移行判断・費用・工程を、稟議とベンダー選定にそのまま使える形で整理します。BigQuery Data Transfer ServiceでのRedshift移行、SUPER型やDISTKEY/SORTKEYの扱い、AWS→GCPのエグレス費用、10TB規模で初期1,000万〜2,000万円・3〜4ヶ月という目安まで解説します。

BigQuery Editions vs On-demand|料金モデルの選び方と損益分岐点【2026年版】 データ基盤
約10分

BigQuery Editions vs On-demand|料金モデルの選び方と損益分岐点【2026年版】

BigQueryの請求書が膨らんできて、Editionsに切り替えるべきか迷う。オンデマンドとEditions(Standard/Enterprise/Enterprise Plus)の料金差、月次スキャン量から見た損益分岐点、INFORMATION_SCHEMAでの使用量把握、Autoscaler設計の勘どころ、規制業界での選び分けまで、稟議と設計会議で使える形で整理しました。

DWHの料金はいくら?費用の見積もり・試算方法を実例で解説 データ基盤
約10分

DWHの料金はいくら?費用の見積もり・試算方法を実例で解説

DWH(データウェアハウス)の料金を、クエリ・ストレージ・付随コストの3要素に分解して整理します。BigQuery・Snowflake・Redshiftの2026年時点の主要単価、小・中・大規模の月額試算シミュレーション、DWH本体だけでは足りない全体費用の見積もり、実績が想定を30〜50%上回る典型3パターン、発注前にベンダーへ確認したいチェックリストまで、費用の全体像を意思決定できる形でまとめました。