マテリアライズド ビューの概要

このページでは、BigQuery マテリアライズド ビューの概要を説明します。

はじめに

マテリアライズド ビューは事前に計算されたビューであり、パフォーマンスと効率の改善を目的としてクエリの結果を定期的にキャッシュに保存します。BigQuery は、事前に計算されたマテリアライズド ビューの結果を利用し、可能であればベーステーブルからの差分のみを読み取って最新の結果を計算します。マテリアライズド ビューに直接クエリを発行できるのはもちろん、ベーステーブルに対するクエリを処理するために BigQuery オプティマイザーでマテリアライズド ビューを使用することもできます。

マテリアライズド ビューを使用したクエリは通常、同じデータをベーステーブルのみから取得するクエリよりも高速で、消費するリソースも少なくて済みます。マテリアライズド ビューは、よく使うクエリを何度も繰り返し使用するような特性を持つワークロードのパフォーマンスを大幅に向上させるのに役立ちます。

BigQuery マテリアライズド ビューの主な特長は次のとおりです。

  • メンテナンス不要: ベーステーブルが変更されると、バックグラウンドでマテリアライズド ビューが再計算されます。ベーステーブルのすべての増分データが自動的にマテリアライズド ビューに追加されます。ユーザー入力は不要です。

  • 常に最新: マテリアライズド ビューは、常にベーステーブル(BigQuery ストリーミング テーブルを含む)の内容と一致します。ベーステーブルが更新、マージ、パーティションの切り捨て、パーティションの有効期限切れによって変更されると、マテリアライズド ビューの影響を受ける部分が無効化され、ベーステーブルの対応する部分が完全に再読み込みされます。パーティション分割されていないマテリアライズド ビューでは、マテリアライズド ビュー全体が無効化され、ベーステーブル全体が再読み込みされます。パーティション分割されているマテリアライズド ビューでは、マテリアライズド ビューの影響を受けるパーティションが無効化され、対応するパーティション全体がベーステーブルから再読み込みされます。追記専用のパーティションは無効化されず、差分モードで読み込まれます。つまり、マテリアライズド ビューに対するクエリによって最新でないデータが返されることは決してありません。

  • スマート チューニング: ソーステーブルに対するクエリまたはクエリの一部がマテリアライズド ビューへのクエリによって解決できる場合は、BigQuery によってマテリアライズド ビューを使用するようにクエリが書き換えられ(クエリの宛先が変更され)、その結果パフォーマンスと効率が向上します。

利点

BigQuery マテリアライズド ビューには次の利点があります。

  • 集計関数を含むクエリの実行時間の短縮とコストの低減。最大のメリットが得られるのは、クエリの計算コストが高く、返されるデータセットが小さい場合です。

  • BigQuery による自動的かつ透過的な最適化。オプティマイザーは、可能であればマテリアライズド ビューを使用してクエリ実行プランを改善します。この最適化のおかげで、クエリを変更する必要はありません。

  • BigQuery テーブルと同じ復元力と高可用性。

ユースケース

BigQuery マテリアライズド ビューは、次のようなユースケースを狙いとしています。

  • クエリ パフォーマンスの高速化: 生のテーブルがあり、膨大な処理を要するオンライン分析処理(OLAP)スタイルの集計を行う場合に、抽出、変換、読み込み(ETL)やビジネス インテリジェンス(BI)パイプラインなどの予測可能で反復的なクエリがあるときは、BigQuery マテリアライズド ビューを使用することをおすすめします。

  • リアルタイム データの集計: リアルタイムの意思決定のためにデータにアクセスする場合、BigQuery はストリーミング機能をネイティブにサポートします。BigQuery マテリアライズド ビューは BigQuery ストリーミングと統合されており、集計をリアルタイムで実行して最新の情報を提供します。

マテリアライズド ビューの作成

マテリアライズド ビューは、Cloud Console、bq コマンドライン ツール、または BigQuery API を使用して作成できます。たとえば、Cloud Console では次の DDL ステートメントを使用できます。

CREATE MATERIALIZED VIEW  project-id.my_dataset.my_mv_table
AS SELECT product_id, SUM(clicks) AS sum_clicks
FROM  project-id.my_dataset.my_base_table
GROUP BY 1

Cloud Console、bq コマンドライン ツール、または BigQuery API を使用して実体化されたビューを作成する方法については、マテリアライズド ビューを作成して使用するをご覧ください。

料金

BigQuery マテリアライズド ビューの料金は、次のコンポーネントに関して発生します。

  • マテリアライズド ビューに対するクエリ
  • マテリアライズド ビューのメンテナンス(ビューの更新時など)
  • マテリアライズド ビューのテーブルの保存
コンポーネント オンデマンド料金 定額料金
クエリ マテリアライズド ビューとベーステーブルの必要な部分によって処理されたバイト数。1 追加料金なし。スロットはクエリの実行中に消費されます。
メンテナンス 処理されたバイト数。スロットは増分ビュー更新のために消費されます。 追加料金なし。スロットはクエリの実行中に消費されます。
保存 マテリアライズド ビューに格納されたバイト数 マテリアライズド ビューに格納されたバイト数

1 ベーステーブルが追記専用の場合、ビューの最後の更新以降の差分のみがベーステーブルから処理されます。詳細については、増分更新をご覧ください。

保存料金の詳細

マテリアライズド ビューの AVGARRAY_AGGAPPROX_COUNT_DISTINCT の各集計値は、最終的な値が直接保存されるわけではありません。その代わりに、最終的な値を生成するための中間的な「スケッチ」として、BigQuery の内部にマテリアライズド ビューが保存されます。

例として、次のコマンドで作成されたマテリアライズド ビューを考えてみます。

CREATE MATERIALIZED VIEW project-id.my_dataset.my_mv_table AS
SELECT date, AVG(net_paid) AS avg_paid
FROM project-id.my_dataset.my_base_table
GROUP BY date

avg_paid 列は NUMERIC または FLOAT64 としてユーザーに表示されますが、内部的には BYTES として保存されます。その内容は、独自形式の中間的なスケッチです。データサイズの計算においては、この列は BYTES として扱われます。

アクセス制御

マテリアライズド ビューに付与するアクセス権は、データセット レベルビューレベル、または列レベルで設定します。IAM リソース階層のより高いレベルでアクセス権を設定することもできます。

マテリアライズド ビューのモニタリング

マテリアライズド ビューとマテリアライズド ビュー更新ジョブに関する情報は、BigQuery API を使用して確認できます。

マテリアライズド ビューの一覧を表示するには、tables.list メソッドを呼び出します。テーブルのスキーマやその他のプロパティを取得するには、tables.get メソッドを呼び出します。

マテリアライズド ビュー更新ジョブの一覧を表示するには、jobs.list メソッドを呼び出します。ジョブの詳細を取得するには、jobs.get メソッドを呼び出します。自動更新ジョブは、ジョブ ID の先頭に materialized_view_refresh という接頭辞が付いており、BigQuery 管理者アカウントによって開始されます。

他の BigQuery 技術との比較

次の表に、BigQuery のキャッシュ、スケジュールされたクエリ、標準ビュー、マテリアライズド ビューの類似点と相違点をまとめます。

コンポーネント キャッシュ スケジュールされたクエリ 標準ビュー マテリアライズド ビュー
パフォーマンス × ×
サポートされるクエリ すべて すべて すべて 集計 - フィルタリングとグループ化
パーティショニングとクラスタリング × 該当せず
増分更新 × × ×
追加の保存 × ×
クエリの書き換え × × ×
メンテナンス費用 × 該当せず
データ未更新 なし なし なし
1 つのテーブルに制限 × × ×

他の BigQuery 機能との連携

次の BigQuery の機能は、マテリアライズド ビューに対して透過的に機能します。

  • クエリプランの説明: クエリプランには、スキャンされたマテリアライズド ビュー(存在する場合)が反映され、マテリアライズド ビューとそのベーステーブルから読み取られたバイト数が示されます。

  • クエリのキャッシュ: マテリアライズド ビューを使用して書き換えられたクエリの結果は、通常の制限(確定関数の使用、ベーステーブルへのストリーミングなし、など)の下でキャッシュに保存できます。

  • コスト計算: オンデマンド課金では、マテリアライズド ビューを使用してクエリが書き換えられた結果、ベーステーブルをスキャンするよりもスキャンバイト数が少なくなった場合、クエリの費用は低減します。

  • コスト制限: 課金バイト数の上限を設定していて、クエリによって読み取られたバイト数がその上限を超えた場合は、そのクエリでマテリアライズド ビュー、ベーステーブル、またはその両方のいずれが使用されていたかにかかわらず、クエリは課金されずに失敗します。

  • ドライランによるコスト推定: ドライランは、使用可能なマテリアライズド ビューを使用してクエリ書き換えロジックを繰り返し、コストを正確に推定します。これは、特定のクエリがマテリアライズド ビューを利用するかどうかを調べる手段となります。

制限事項

  • マテリアライズド ビューを直接操作すること、またはマテリアライズド ビューから生の内容を読み取ることはできません。つまり、次の操作はサポートされていません。

    • マテリアライズド ビューを、コピージョブのコピー元またはコピー先としてコピーすること
    • マテリアライズド ビューのエクスポート
    • マテリアライズド ビューへのデータの読み込み
    • マテリアライズド ビューへのクエリ結果の書き込み
    • マテリアライズド ビューに対する DML ステートメントの実行
  • マテリアライズド ビューは、ベーステーブルと同じデータセットに存在する必要があります。

  • マテリアライズド ビューでは、制限付き SQL 構文と一部の集計関数がサポートされています。詳細については、サポートされているマテリアライズド ビューをご覧ください。

  • マテリアライズド ビューでは 1 つのテーブルのみを参照でき、結合や UNNEST 機能は使用できません。

  • マテリアライズド ビューを他のマテリアライズド ビューにネストすることはできません。

  • マテリアライズド ビューには標準 SQL 言語のみを使用できます。

  • ベーステーブルごとに最大 20 個のマテリアライズド ビューを作成できます。

  • SHOW DDL ステートメントは、マテリアライズド ビューではサポートされていません。

  • ALTER DDL ステートメント(SET OPTIONS 付きの ALTER を除く)は、マテリアライズド ビューではサポートされていません。

  • 先にマテリアライズド ビューを削除せずにベーステーブルを削除した場合、マテリアライズド ビューに対するクエリは失敗し、更新も失敗します。ベーステーブルを再作成する場合は、マテリアライズド ビューも再作成する必要があります。

  • Cloud Key Management Service 鍵を使用したデータの保護はサポートされていません。Cloud KMS 鍵を使用して、マテリアライズド ビューでデータを保護することはできません。また、Cloud KMS 鍵で保護されたベーステーブルにマテリアライズド ビューを作成することもできません。

ARRAY_AGG に関する注意事項

マテリアライズド ビューから ARRAY_AGG 列を選択する場合は、ベーステーブルから選択するときに ARRAY_AGG を使用する場合と同じ制限が課されます。RESPECT NULLS の場合(これはデフォルトで設定されています)、出力配列に NULL の要素を含めることはできません。出力配列の要素に NULL が含まれている場合はエラーが発生します。

次のマテリアライズド ビューの場合、

CREATE MATERIALIZED VIEW project-id.my_dataset.my_mv_table AS
SELECT
  column_1, ARRAY_AGG(column_2 ORDER BY column_3 DESC LIMIT 4) column_arr
FROM `project.dataset.base_table`
GROUP BY column_1

次のクエリは失敗します。

SELECT * FROM project-id.my_dataset.my_mv_table

エラーの詳細は次のとおりです。

query: Array cannot have a null element; error in writing field

このエラーを回避するには、ARRAY_AGGIGNORE NULLS を追加します。

ARRAY_AGG(col_2 ORDER BY col_3 DESC LIMIT 4 IGNORE NULLS) col

別の方法として、'%t' または '%T' 指定子を使用して出力配列の列の書式を設定することもできます。

SELECT column_1, FORMAT('%T', column_arr) FROM project-id.my_dataset.my_mv_table

結合に関する注意事項

結合は現在サポートされていませんが、マテリアライズド ビューを利用することで、結合とともに集計を行うクエリのコストとレイテンシを低減できる場合があります。たとえば、大きなファクト テーブルをいくつかの小さなディメンション テーブルと結合してから、それを基に集計を行う場合を考えてみます。このようなクエリは、まず外部キーをグループ化キーとしてファクト テーブルで集計を行い、その結果をディメンション テーブルと結合してから、最後に事後集計を行うように書き換えると、実用的になる可能性があります。

この方法を具体的に示すために、TPC-DS ベンチマークのクエリ 52 番を使用します。

元のクエリは次のとおりです。

SELECT  dt.d_year,
   item.i_brand_id brand_id,
   item.i_brand brand,
 SUM(ss_ext_sales_price) ext_price
 FROM project.tpcds_10T.date_dim dt,
   project.tpcds_10T.store_sales,
   project.tpcds_10T.item
 WHERE dt.d_date_sk = store_sales.ss_sold_date_sk
    and store_sales.ss_item_sk = item.i_item_sk
    and item.i_manager_id = 1
    and dt.d_moy=12
    and dt.d_year=1998
 GROUP BY dt.d_year,
   item.i_brand,
   item.i_brand_id
 ORDER BY dt.d_year,
   ext_price DESC,
   brand_id
LIMIT 100

書き換え後のクエリは次のとおりです。

WITH sales_summary AS (
  SELECT ss_sold_date_sk,
    ss_item_sk,
    SUM(ss_ext_sales_price) AS ext_price
  FROM project.tpcds_10T.store_sales
  GROUP BY ss_sold_date_sk, ss_item_sk
)
SELECT dt.d_year,
  item.i_brand_id brand_id,
  item.i_brand brand,
  SUM(ext_price) AS ext_price
FROM sales_summary,
  project.tpcds_10T.date_dim dt,
  project.tpcds_10T.item
WHERE sales_summary.ss_sold_date_sk = dt.d_date_sk
  AND sales_summary.ss_item_sk = item.i_item_sk
    AND item.i_manager_id = 1
    AND dt.d_moy=12
    AND dt.d_year=1998
GROUP BY dt.d_year,
  item.i_brand,
  item.i_brand_id
ORDER BY dt.d_year,
  ext_price desc,
  brand_id
LIMIT 100

ビューを作成する方法は次のとおりです。

CREATE OR REPLACE MATERIALIZED VIEW project-id.tpcds_10T.sales_summary_mv AS
  SELECT
    ss_sold_date_sk,
    ss_item_sk,
    SUM(ss_ext_sales_price) AS ext_price
  FROM project-id.tpcds_10T.store_sales
  GROUP BY ss_sold_date_sk, ss_item_sk

このマテリアライズド ビューをディメンション テーブルと結合する方法は次のとおりです。

SELECT dt.d_year,
  item.i_brand_id brand_id,
  item.i_brand brand,
  SUM(ext_price) as ext_price
FROM sales_summary_mv,
  project.tpcds_10T.date_dim dt,
  project.tpcds_10T.item
WHERE sales_summary.ss_sold_date_sk = dt.d_date_sk
  AND sales_summary.ss_item_sk = item.i_item_sk
    AND item.i_manager_id = 1
    AND dt.d_moy=12
    AND dt.d_year=1998
GROUP BY dt.d_year,
  item.i_brand,
  item.i_brand_id
ORDER BY dt.d_year,
  ext_price desc,
  brand_id
LIMIT 100

次のステップ