- 「ロードせず問い合わせる」4 つの経路(外部テーブル・BigLake テーブル・フェデレーテッドクエリ・BigQuery Omni)の使い分け
- BigLake テーブルが外部テーブルと決定的に違う点 — アクセス委任とメタデータキャッシュ
- Apache Iceberg 対応の 2 つの形態(外部テーブルとマネージドテーブル)の見分け方
- オブジェクトテーブルで非構造化データを SQL の世界に引き込む方法
- 鮮度・性能・ガバナンス・コストの 4 軸で外部データの選択肢を評価する方法
前提: ハンズオン 10-1 はサンドボックスで完走可・無料枠内。10-2 と 10-3 は課金プロジェクト必須(概算 数円)。
「ロードしない」という選択肢
第 3 章では、外部のデータを BigQuery のネイティブストレージへロードして使う方法を学びました。ロードには「クエリが速い」「BigQuery のフル機能が使える」という利点がありますが、裏を返せば「コピーを作る」ということです。元データが更新されるたびに再ロードが必要になり、ストレージも二重に持つことになります。
BigQuery には、データを移動させずにその場でクエリするための経路が複数あります。代表的なものが次の 4 つです。
共通点は「BigQuery のネイティブストレージにデータを複製しない」こと。違いは、誰が元データへの権限を持つかとメタデータをキャッシュできるかです。この 2 点が、この章全体を貫く軸になります。
storage.objectViewer を配って回るのか、BigLake テーブルでアクセスを委任し BigQuery の IAM だけで完結させるのかは、早い段階で決めておく価値があります。BigLake テーブル — アクセス委任とメタデータキャッシュ
BigLake テーブルは、Cloud Storage・Amazon S3・Azure Blob Storage 上の構造化データを、通常の外部テーブルと同じ CREATE EXTERNAL TABLE 文の延長で扱えるようにする仕組みです。ただし Amazon S3・Azure Blob Storage 上に作る場合は BigQuery Omni の扱いになり、データセット自体を Omni 対応リージョン(aws-us-east-1 など)に作成する必要があります。本書既定の US マルチリージョンのデータセットに作れるのは Cloud Storage の BigLake テーブルだけです(Omni は後述)。公式ドキュメントは通常の外部テーブルとの違いを次のように説明しています。
Access delegation decouples access to the BigLake table from access to the underlying data store.
普通の外部テーブルでは、クエリを投げるユーザー本人が「外部テーブルへの権限」と「Cloud Storage バケットそのものへの権限」の両方を持っている必要があります。BigLake テーブルでは、BigQuery Connection リソースに紐づくサービスアカウントがバケットへのアクセス権限を持ち、ユーザーは BigLake テーブルへの IAM 権限だけを持てば十分になります。バケットの権限管理をデータエンジニアリング側に集約し、分析者には行レベル・列レベルセキュリティを含む BigQuery 側の権限モデルだけを意識させられるのが利点です。
メタデータキャッシュは、ファイル数が多い外部データセットで特に効果を発揮します。クエリのたびに Cloud Storage のファイル一覧を取得し直すのではなく、キャッシュされたメタデータ(ファイル名・パーティション情報・行数など)を使うことでプランニングが速くなります。対応するのはオブジェクトテーブル、Amazon S3 BigLake テーブル、Cloud Storage BigLake テーブルの 3 種類で、素の Cloud Storage 外部テーブルにはこの機能はありません。
| 比較軸 | 外部テーブル | BigLake テーブル |
|---|---|---|
| データストアへの権限 | クエリするユーザー本人が必要 | Connection のサービスアカウントに委任 |
| 行・列レベルセキュリティ | 非対応 | 対応 |
| メタデータキャッシュ | 非対応 | 対応(staleness 30 分〜7 日) |
| 対応データソース | Cloud Storage・Google Drive・Bigtable 等 | Cloud Storage・Amazon S3・Azure Blob Storage |
Apache Iceberg 対応 — 「外部」と「マネージド」を区別する
Apache Iceberg はオープンなテーブルフォーマットで、複数のクエリエンジン(Spark・Trino・BigQuery など)から同じデータを読み書きできることが最大の価値です。BigQuery の Iceberg 対応は、性質の異なる 2 つの機能に分かれています。名前が紛らわしいので、現行ドキュメントの表記を正として整理します。
- Apache Iceberg external tables(Iceberg 外部テーブル) — Spark や Trino など他のエンジンがすでに書き込んでいる Iceberg データを、読み取り専用で BigQuery から参照する外部テーブル。Iceberg のメタデータファイル(
*.metadata.json)を指すか、Lakehouse ランタイムカタログ/AWS Glue Data Catalog 経由で接続する - Apache Iceberg managed tables(Iceberg マネージドテーブル) — BigQuery がテーブルそのものを管理するフルマネージドテーブル。DML・スキーマ進化・タイムトラベルに対応しつつ、実データは Parquet 形式で自分の Cloud Storage バケットに保存され、Iceberg フォーマットとして他エンジンからも読み取れる。旧称は「BigLake tables for Apache Iceberg in BigQuery」で、2026 年時点のドキュメントではこの旧称から改称されている
Iceberg マネージドテーブルの作成は、通常の CREATE TABLE に table_format = 'ICEBERG' と保存先を指定するだけです。
CREATE TABLE `PROJECT_ID.handson_ch10.iceberg_events`
(
event_id INT64,
event_name STRING,
event_ts TIMESTAMP
)
WITH CONNECTION `PROJECT_ID.us.biglake_conn`
OPTIONS (
file_format = 'PARQUET',
table_format = 'ICEBERG',
storage_uri = 'gs://PROJECT_ID-bq-handson/iceberg/events'
);
一方、Iceberg 外部テーブルは既存の Iceberg メタデータファイルを指すだけです。
CREATE EXTERNAL TABLE `PROJECT_ID.handson_ch10.iceberg_external`
WITH CONNECTION `PROJECT_ID.us.biglake_conn`
OPTIONS (
format = 'ICEBERG',
uris = ['gs://other-team-bucket/lake/events/metadata/00003.metadata.json']
);
Iceberg 外部テーブルには注意点があります。参照する metadata.json は手動で最新のものに更新する必要があり、他エンジンが新しいスナップショットを書いても自動追従しません。頻繁に更新されるテーブルを他エンジンと共有するなら、マネージドテーブルか、カタログ経由(AWS Glue Data Catalog・Lakehouse ランタイムカタログ)での接続を検討してください。
オブジェクトテーブル・フェデレーテッドクエリ・Omni・Drive 連携
非構造化データにも SQL で触れる仕組みがあります。オブジェクトテーブルは Cloud Storage 上の画像・PDF・音声などのファイルを、uri・content_type・size といった固定スキーマの読み取り専用テーブルとして見せます。ファイル本体はテーブルに取り込まれず、参照だけが行と対応します。
CREATE EXTERNAL TABLE `PROJECT_ID.handson_ch10.product_images`
WITH CONNECTION `PROJECT_ID.us.biglake_conn`
OPTIONS (
object_metadata = 'SIMPLE',
uris = ['gs://PROJECT_ID-bq-handson/images/*']
);
オブジェクトテーブルの真価は、AI.GENERATE_TEXT・ML.ANNOTATE_IMAGE・ML.PROCESS_DOCUMENT といった AI 関数と組み合わせ、画像や文書に対して SQL 一発で推論をかけられる点にあります。この使い方は第 14 章(オブジェクトテーブルと AI 活用)で本格的に扱います。ここでは「非構造化データを SQL の世界に引き込む入口」として位置づけを押さえておいてください。
フェデレーテッドクエリは、AlloyDB・Spanner・Cloud SQL(および 2026-08 時点でプレビューの SAP Datasphere)に対して、その場でクエリを送り結果を一時テーブルとして受け取る仕組みです。EXTERNAL_QUERY 関数を使います。
SELECT *
FROM EXTERNAL_QUERY(
'PROJECT_ID.us.cloudsql_conn',
'SELECT order_id, status FROM orders WHERE status != ''CANCELLED'''
);
実行される SQL は接続先データベースの方言(MySQL / PostgreSQL 等)で書き、読み取り専用に限られます。パフォーマンスはネイティブの BigQuery テーブルより劣り、クロスリージョンのクエリには 1 日あたり 1 TB という上限があるため、大量データの定常的な分析には向きません。「トランザクション DB の最新状態と BigQuery 側の分析データを都度突き合わせたい」といった、小〜中規模のルックアップ用途に向いています。
BigQuery Omni は、Amazon S3・Azure Blob Storage に置いたままのデータに対して BigQuery のクエリエンジンを実行する仕組みです。データを Google Cloud 側に移動させず、コンピュートの方をデータの近く(AWS 6 リージョン・Azure 1 リージョンで提供)に配置します。BigQuery の料金モデルがそのまま適用されますが、DML・BigQuery ML・JavaScript UDF は非対応で、クロスクラウドのデータ転送にはエグレス料金がかかります。「マルチクラウドでデータがサイロ化しているが、分析基盤は BigQuery に統一したい」という組織向けの選択肢です。
Google スプレッドシートや Google ドライブ上のファイルも、Cloud Storage と同様に外部テーブルとして参照できます。スプレッドシートを都度エクスポートする運用から抜け出し、業務部門が更新するシートを BigQuery 側からそのまま SQL で読みに行けるのが利点です。ただし更新頻度の高い共同編集シートを分析の主データソースにするのは避け、あくまで補助的なマスタデータの参照に留めるのが安全です。
| 選択肢 | 鮮度 | 性能 | ガバナンス | コスト傾向 |
|---|---|---|---|---|
| ロード | 再ロードするまで固定 | 最速 | BigQuery IAM のみ | ストレージ二重化 |
| 外部テーブル | 常に最新 | キャッシュ無しでやや遅い | データストア側の権限が必要 | ストレージは元のまま |
| BigLake テーブル | staleness 設定に依存 | キャッシュで改善 | アクセス委任で BigQuery 側に集約 | Connection 管理コスト |
| フェデレーテッドクエリ | 常に最新 | 低い(都度転送) | 接続先 DB の権限が必要 | 転送量に依存 |
公開の GCS バケットにある小さな CSV を外部テーブルとして参照し、同じデータをロードしたテーブルと見比べます。サンドボックスで完走可・無料枠内(スキャン量は数十 KB 程度)。自分のバケットは作りません。
- 演習用データセットを作成します(ロケーションは US)。
- 外部テーブルを作成します。
bq mk --location=US --dataset PROJECT_ID:handson_ch10
CREATE OR REPLACE EXTERNAL TABLE `PROJECT_ID.handson_ch10.states_external`
(
name STRING,
post_abbr STRING
)
OPTIONS (
format = 'CSV',
uris = ['gs://cloud-samples-data/bigquery/us-states/us-states.csv'],
skip_leading_rows = 1
);
- クエリを実行し、外部テーブルの内容を確認します(dry run で処理バイト量も確認します)。
-- 処理: 数十 KB 程度(実測は dry run / エディタ右上の見積もりで確認)
SELECT name, post_abbr
FROM `PROJECT_ID.handson_ch10.states_external`
WHERE post_abbr IN ('CA', 'TX', 'NY');
期待される出力: California/CA、Texas/TX、New York/NY の 3 行。
- 同じデータをロードしたテーブルを作り、クエリを再実行して速度感を比べます。
bq load --location=US --autodetect --source_format=CSV \
handson_ch10.states_loaded \
gs://cloud-samples-data/bigquery/us-states/us-states.csv
外部テーブルはクエリのたびに Cloud Storage へアクセスするため、初回実行にわずかな遅延が乗ります。データ量が小さい今回はほぼ体感できませんが、ファイル数・データ量が増えるほど差が開きます。
後片付け:
bq rm -r -f -d PROJECT_ID:handson_ch10
Cloud Storage バケットと BigQuery Connection を作り、BigLake テーブル経由でアクセスを委任します。課金プロジェクト必須(バケット作成・少量のクエリで概算数円)。
- 作業用バケットと Connection を作成します(Connection のロケーションはデータセットと合わせて US)。
gcloud storage buckets create gs://PROJECT_ID-bq-handson --location=us
bq mk --connection --location=US \
--connection_type=CLOUD_RESOURCE \
biglake_conn
bq show --location=US --connection PROJECT_ID.us.biglake_conn
# 出力の serviceAccountId をメモする
- Connection のサービスアカウントに、バケットへの読み取り権限を付与します。
gcloud storage buckets add-iam-policy-binding gs://PROJECT_ID-bq-handson \
--member="serviceAccount:CONNECTION_SERVICE_ACCOUNT" \
--role="roles/storage.objectViewer"
echo "name,post_abbr" > /tmp/states.csv
echo "California,CA" >> /tmp/states.csv
gcloud storage cp /tmp/states.csv gs://PROJECT_ID-bq-handson/states/states.csv
- BigLake テーブルを、メタデータキャッシュを有効にして作成します。
CREATE OR REPLACE EXTERNAL TABLE `PROJECT_ID.handson_ch10.states_biglake`
(
name STRING,
post_abbr STRING
)
WITH CONNECTION `PROJECT_ID.us.biglake_conn`
OPTIONS (
format = 'CSV',
uris = ['gs://PROJECT_ID-bq-handson/states/*.csv'],
skip_leading_rows = 1,
max_staleness = INTERVAL 1 HOUR,
metadata_cache_mode = 'AUTOMATIC'
);
-- 処理: 1 KB 未満(無料枠内)
SELECT * FROM `PROJECT_ID.handson_ch10.states_biglake`;
期待される出力: California/CA の 1 行。このテーブルへの SELECT 権限だけを持つユーザーは、バケット自体への権限を一切持たなくてもクエリできることを確認してください(Connection のサービスアカウントが代行しています)。
後片付け:
bq rm -r -f -d PROJECT_ID:handson_ch10
bq rm --connection --location=US PROJECT_ID.us.biglake_conn
gcloud storage rm -r gs://PROJECT_ID-bq-handson
BigQuery が管理する Iceberg テーブルを作成し、DML で更新します。DML はサンドボックスでは実行できないため課金プロジェクト必須(概算数円)。ハンズオン 10-2 で作成した Connection とデータセットを使い回します(削除済みの場合は再作成してください)。
- Iceberg マネージドテーブルを作成します。
CREATE TABLE `PROJECT_ID.handson_ch10.iceberg_events`
(
event_id INT64,
event_name STRING,
event_ts TIMESTAMP
)
WITH CONNECTION `PROJECT_ID.us.biglake_conn`
OPTIONS (
file_format = 'PARQUET',
table_format = 'ICEBERG',
storage_uri = 'gs://PROJECT_ID-bq-handson/iceberg/events'
);
- DML でデータを投入し、更新します。
INSERT INTO `PROJECT_ID.handson_ch10.iceberg_events`
VALUES (1, 'signup', CURRENT_TIMESTAMP()),
(2, 'purchase', CURRENT_TIMESTAMP());
UPDATE `PROJECT_ID.handson_ch10.iceberg_events`
SET event_name = 'purchase_completed'
WHERE event_id = 2;
SELECT * FROM `PROJECT_ID.handson_ch10.iceberg_events` ORDER BY event_id;
期待される出力: event_id=1 は signup、event_id=2 は purchase_completed の 2 行。通常の外部テーブルでは INSERT / UPDATE は使えませんが、Iceberg マネージドテーブルは BigQuery のネイティブテーブルと同じ DML が使えます。裏側の Cloud Storage バケットを確認すると、Parquet ファイルと Iceberg のメタデータ(スナップショット履歴)が生成されていることが分かります。
後片付け:
bq rm -r -f -d PROJECT_ID:handson_ch10
bq rm --connection --location=US PROJECT_ID.us.biglake_conn
gcloud storage rm -r gs://PROJECT_ID-bq-handson
つまずきポイント
CREATE EXTERNAL TABLE がエラーになります。本書は一貫して US(マルチリージョン)を使っていますが、既存プロジェクトで別ロケーションのバケットを使う場合は、データセット側もそのロケーションに合わせる必要があります。storage.objectViewer 権限が付与されていないとクエリは失敗します。「テーブルへの権限」と「委任先サービスアカウントへの権限」は別物として、両方を確認してください。理解度チェック
Q1. 外部テーブルと BigLake テーブルの本質的な違いは何ですか?
アクセス委任の有無です。外部テーブルはクエリするユーザー本人がデータストアへの権限も持つ必要がありますが、BigLake テーブルは Connection のサービスアカウントが権限を代行するため、ユーザーは BigLake テーブルへの権限だけで済みます。加えて BigLake テーブルはメタデータキャッシュと行・列レベルセキュリティにも対応します。
Q2. BigLake テーブルのメタデータキャッシュにおける max_staleness の設定可能範囲は?
30 分から 7 日の間で指定します。自動更新モードでは通常 30〜60 分間隔でキャッシュが更新され、手動更新モードでは BQ.REFRESH_EXTERNAL_METADATA_CACHE システムプロシージャで明示的に更新します。
Q3. Apache Iceberg external tables と Apache Iceberg managed tables の違いを説明してください。
external tables は他のエンジン(Spark・Trino 等)が書き込んだ Iceberg データを読み取り専用で参照するものです。managed tables は BigQuery 自身がテーブルのライフサイクルを管理し、DML・スキーマ進化・タイムトラベルに対応するフルマネージドテーブルで、旧称は「BigLake tables for Apache Iceberg in BigQuery」でした。
Q4.(シナリオ)Spark と Trino がすでに書き込んでいる本番の Iceberg データレイクを、BigQuery からは分析目的の読み取りだけに使いたい。BigQuery 側からの書き込みは想定していません。最適な選択肢は?
A. Cloud Storage 外部テーブル B. BigLake テーブル(CSV/Parquet) C. Apache Iceberg managed tables D. Apache Iceberg external tables
D。 書き込みが他エンジン側にあるため、BigQuery 側は読み取り専用の Iceberg external tables で十分です。A は Iceberg のスナップショット・スキーマ進化を意識した読み取りができません。B は Iceberg フォーマットを直接扱う機能ではありません。C は BigQuery 側に書き込み管理を持たせる機能で、他エンジンが主体の運用には噛み合いません。
Q5.(シナリオ)新規にデータレイクテーブルを BigQuery 上で立ち上げ、DML による更新・スキーマ進化・タイムトラベルを活用しつつ、将来的に他エンジンからもオープンフォーマットで読めるようにしておきたい。最適な選択肢は?
A. Cloud Storage 外部テーブル B. フェデレーテッドクエリ C. Apache Iceberg managed tables D. Apache Iceberg external tables
C。 BigQuery 側で DML・スキーマ進化・タイムトラベルを使いながらデータを管理し、実体は Iceberg フォーマットで Cloud Storage に保存されるため他エンジンからも読めます。A は DML 非対応、B はそもそもテーブルを作る機能ではなく都度クエリを転送するだけ、D は他エンジンが書いたデータを読むための機能で新規構築には向きません。
まとめと次章へ
- データが動き続けているなら、外部テーブル・BigLake テーブル・フェデレーテッドクエリのいずれかで「その場に置いたまま」問い合わせる選択肢がある
- BigLake テーブルは外部テーブルにアクセス委任とメタデータキャッシュを足したもの。権限管理を BigQuery 側に集約したいときの標準解
- Apache Iceberg 対応は「external tables(読み取り専用)」と「managed tables(BigQuery が書き込みを管理するフルマネージド、旧称 BigLake tables for Apache Iceberg in BigQuery)」の 2 つを区別する
- オブジェクトテーブルは非構造化データを SQL に引き込む入口。AI 関数との組み合わせは第 14 章で扱う
- フェデレーテッドクエリと BigQuery Omni は「読むだけで理解が完結する」機能として、必要になったときに選択肢として思い出せれば十分