キャッシュに保存されているクエリ結果を使用する

このドキュメントでは、BigQuery のキャッシュに保存されているクエリ結果を使用する方法について説明します。

概要

BigQuery はすべてのクエリ結果をテーブルに書き込みます。テーブルはユーザーが明示的に指定したテーブルか(宛先テーブル)、一時的なキャッシュ結果テーブルのいずれかです。一時的なキャッシュ結果テーブルは、ユーザー別、プロジェクト別に保持されます。一時的なテーブルにはストレージの費用がかかりませんが、永続的なテーブルにクエリ結果を書き込むと、そのデータの保存に対して課金されます。

インタラクティブ クエリとバッチクエリの両方を含むすべてのクエリの結果は、一部の例外を除いて、一時テーブルに約 24 時間キャッシュされます。

制限事項

クエリ キャッシュの使用には以下の制限があります。

  • 同じクエリを重複して実行すると、BigQuery はキャッシュに保存された結果を再利用しようとします。キャッシュからデータを取得するには、複製されたクエリテキストを元のクエリと完全に同じにする必要があります。
  • クエリ結果がキャッシュ結果テーブルに存続するためには、結果セットを最大レスポンス サイズよりも小さくする必要があります。サイズの大きな結果セットの管理について詳しくは、大きいクエリ結果を返すをご覧ください。
  • キャッシュ結果テーブルは DML ステートメントのターゲットにできません。
  • 現在のセマンティクスでは可能ですが、キャッシュに保存された結果を従属ジョブの入力として使用することは推奨されません。たとえば、キャッシュ テーブルから結果を取得するクエリジョブを送信しないでください。その代わりに、結果を名前付き宛先テーブルに書き込んでください。簡単にクリーンアップできるよう、データセット レベルの defaultTableExpirationMs プロパティなどの機能でデータを一定期間後に自動的に期限切れにできます。

料金と割り当て

クエリ結果がキャッシュ結果テーブルから取得された場合、ジョブ統計プロパティ statistics.query.cacheHittrue として返され、そのクエリについては課金されません。キャッシュに保存された結果を使用したクエリは、課金の対象となりませんが、BigQuery の割り当てポリシーの対象にはなります。キャッシュに保存された結果を使用したクエリには、コスト削減に加えて、非常に高速であるという利点もあります。これは BigQuery が結果セットを計算する必要がないためです。

クエリのキャッシュの例外

次の場合、クエリ結果はキャッシュに保存されません。

  • 宛先テーブルが、ジョブ構成、Cloud Console、従来のウェブ UI、bq コマンドライン ツール、または API で指定されている場合
  • 結果がキャッシュに保存された後で、参照するテーブルまたは論理ビューが変更された
  • クエリによって参照されているいずれかのテーブルが最近ストリーミング挿入を受信していたとき(ストリーミング バッファがテーブルに添付されている)。そのテーブルが新しい行を受け取ったかどうかは問いません
  • CURRENT_TIMESTAMP()NOW() といった日時関数や CURRENT_USER() 関数など、実行タイミングによって異なる値を返す非決定性関数がクエリで使用されている場合
  • ワイルドカードを使用して複数のテーブルに対してクエリを実行する場合
  • キャッシュに保存された結果が期限切れとなった場合。通常、キャッシュのライフタイムは 24 時間ですが、キャッシュへの保存はベスト エフォート式であり、すぐに無効になることがあります
  • クエリが外部データソースに対して実行されている場合

キャッシュされた結果の保存方法

クエリを実行すると、一時的なキャッシュ結果テーブルは「匿名データセット」と呼ばれる特別なデータセットに作成されます。匿名データセットに対するアクセス権は、IAM リソース階層モデル(プロジェクトと組織の権限)から権限を継承する通常のデータセットとは異なり、データセット所有者に限られます。匿名データセットの所有者は、キャッシュされた結果を生成したクエリを実行したユーザーです。

匿名データセットが作成されると、クエリジョブを実行するユーザーには、匿名データセットに対する bigquery.dataOwner アクセス権が明示的に付与されます。bigquery.dataOwner アクセス権は、クエリジョブを実行したユーザーだけにデータセット全体を制御する権限を与えます。この権限には、匿名データセットのキャッシュ結果テーブル全体を制御する権限が含まれます。クエリ結果を共有する場合は、匿名データセットに格納されたキャッシュ結果を使用しないでください。その代わりに、結果を名前付き宛先テーブルに書き込んでください。

クエリを実行するユーザーは、データセットとキャッシュ結果テーブルへの完全アクセス権を持っていますが、従属ジョブの入力としてそれらを使用することは推奨されません。

匿名データセットの名前の先頭はアンダースコアです。これにより、Cloud Console と従来の BigQuery ウェブ UI のデータセットのリストで匿名データセットが非表示になります。bq コマンドライン ツールまたは API を使用して、匿名データセットを一覧表示し、匿名データセットのアクセス制御を監査できます。

キャッシュに保存されている結果の取得を無効にする

[Use cached results] オプションでは、クエリ対象のテーブルが変更された場合を除いて、以前に実行された同じクエリの結果が再利用されます。キャッシュされた結果の使用が役立つのは、クエリを繰り返し実行する場合のみです。新規のクエリでは [Use cached results] オプションの効果がありませんが、デフォルトで有効になっています。

[Use cached results] オプションを無効にしてクエリを繰り返し実行すると、既存のキャッシュされた結果が上書きされます。この場合、BigQuery でクエリ結果を計算する必要があり、そのクエリに対して課金が発生します。これは、ベンチマークに非常に役立ちます。

キャッシュされた結果の取得を無効にしてクエリジョブの実行評価を強制的に行う場合は、クエリジョブの configuration.query.useQueryCache プロパティを false に設定します。

[キャッシュされた結果を使用] オプションを無効にするには:

Console

  1. Cloud Console を開きます。
    [BigQuery] ページに移動

  2. [クエリを新規作成] をクリックします。

  3. [クエリエディタ] テキスト領域に有効な SQL クエリを入力します。

  4. [展開] をクリックして、[クエリの設定] を選択します。

    クエリの設定

  5. [キャッシュの設定] の [キャッシュされた結果を使用] をオフにします。

    キャッシュに保存された結果オプション

従来の UI

  1. 従来の BigQuery ウェブ UI に移動します。
    BigQuery ウェブ UI に移動

  2. [Compose query] ボタンをクリックします。

  3. [New Query] テキスト領域に有効な SQL クエリを入力します。

  4. [Show Options] をクリックします。

  5. [Use Cached Results] をオフにします。

キャッシュに保存された結果オプション

bq

クエリ キャッシュを上書きするには、nouse_cache フラグを指定します。次の例では、BigQuery が既存のキャッシュされた結果を使用することなく、クエリを強制的に処理します。

 bq query \
 --nouse_cache \
 --batch \
 'SELECT
    name,
    count
  FROM
    `my-project`.mydataset.names_2013
  WHERE
    gender = "M"
  ORDER BY
    count DESC
  LIMIT
    6'

API

キャッシュに保存されている結果を使用せずにクエリを処理するには、query ジョブ構成で useQueryCache プロパティを false に設定します。

Go

このサンプルを試す前に、BigQuery クイックスタート: クライアント ライブラリの使用の Go の手順に従って設定を行ってください。詳細については、BigQuery Go API のリファレンス ドキュメントをご覧ください。

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/bigquery"
	"google.golang.org/api/iterator"
)

// queryDisableCache demonstrates issuing a query and requesting that the query cache is bypassed.
func queryDisableCache(w io.Writer, projectID string) error {
	// projectID := "my-project-id"
	ctx := context.Background()
	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("bigquery.NewClient: %v", err)
	}
	defer client.Close()

	q := client.Query(
		"SELECT corpus FROM `bigquery-public-data.samples.shakespeare` GROUP BY corpus;")
	q.DisableQueryCache = true
	// Location must match that of the dataset(s) referenced in the query.
	q.Location = "US"

	// Run the query and print results when the query job is completed.
	job, err := q.Run(ctx)
	if err != nil {
		return err
	}
	status, err := job.Wait(ctx)
	if err != nil {
		return err
	}
	if err := status.Err(); err != nil {
		return err
	}
	it, err := job.Read(ctx)
	for {
		var row []bigquery.Value
		err := it.Next(&row)
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		fmt.Fprintln(w, row)
	}
	return nil
}

Java

キャッシュに保存されている結果を使用せずにクエリを処理するには、QueryJobConfiguration の作成時に setUseQueryCachefalse に設定します。

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.QueryJobConfiguration;
import com.google.cloud.bigquery.TableResult;

// Sample to running a query with the cache disabled.
public class QueryDisableCache {

  public static void runQueryDisableCache() {
    String query = "SELECT corpus FROM `bigquery-public-data.samples.shakespeare` GROUP BY corpus;";
    queryDisableCache(query);
  }

  public static void queryDisableCache(String query) {
    try {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();

      QueryJobConfiguration queryConfig =
          QueryJobConfiguration.newBuilder(query)
              // Disable the query cache to force live query evaluation.
              .setUseQueryCache(false)
              .build();

      TableResult results = bigquery.query(queryConfig);

      results
          .iterateAll()
          .forEach(row -> row.forEach(val -> System.out.printf("%s,", val.toString())));

      System.out.println("Query disable cache performed successfully.");
    } catch (BigQueryException | InterruptedException e) {
      System.out.println("Query not performed \n" + e.toString());
    }
  }
}

Node.js

このサンプルを試す前に、BigQuery クイックスタート: クライアント ライブラリの使用の Node.js の設定手順を実施してください。詳細については、BigQuery Node.js API のリファレンス ドキュメントをご覧ください。

// Import the Google Cloud client library
const {BigQuery} = require('@google-cloud/bigquery');

async function queryDisableCache() {
  // Queries the Shakespeare dataset with the cache disabled.

  // Create a client
  const bigquery = new BigQuery();

  const query = `SELECT corpus
    FROM \`bigquery-public-data.samples.shakespeare\`
    GROUP BY corpus`;
  const options = {
    query: query,
    // Location must match that of the dataset(s) referenced in the query.
    location: 'US',
    useQueryCache: false,
  };

  // Run the query as a job
  const [job] = await bigquery.createQueryJob(options);
  console.log(`Job ${job.id} started.`);

  // Wait for the query to finish
  const [rows] = await job.getQueryResults();

  // Print the results
  console.log('Rows:');
  rows.forEach(row => console.log(row));
}

Python

このサンプルを試す前に、BigQuery クイックスタート: クライアント ライブラリの使用の Python の手順に従って設定を行ってください。詳細については、BigQuery Python API のリファレンス ドキュメントをご覧ください。

from google.cloud import bigquery

# Construct a BigQuery client object.
client = bigquery.Client()

job_config = bigquery.QueryJobConfig(use_query_cache=False)
sql = """
    SELECT corpus
    FROM `bigquery-public-data.samples.shakespeare`
    GROUP BY corpus;
"""
query_job = client.query(sql, job_config=job_config)  # Make an API request.

for row in query_job:
    print(row)

キャッシュを確実に使用する

jobs.insert 関数を使用してクエリを実行する場合、copy ジョブ構成の createDisposition プロパティを CREATE_NEVER に設定することで、キャッシュに保存されている結果を使用できないときはクエリジョブを強制的に失敗させることができます。

クエリ結果がキャッシュに存在しない場合は、NOT_FOUND エラーが返されます。

キャッシュの使用を検証する

BigQuery がキャッシュを使用して結果を返したかどうかを判定する方法は 2 つあります。

  • Cloud Console や従来の BigQuery ウェブ UI を使用している場合は、結果の文字列に処理バイト数に関する情報が含まれず、「キャッシュ済み」という単語が表示されます。

    UI のキャッシュ インジケーター

  • BigQuery API を使用している場合は、クエリ結果の cacheHit プロパティが true に設定されます。

列レベルのセキュリティの影響

デフォルトでは、BigQuery はクエリ結果を 24 時間キャッシュに保存しますが、前述の例外があります。24 時間のキャッシュ保存は、ポリシータグを使用する列レベル セキュリティで保護されているデータのクエリにも適用されます。ポリシータグに使用されている「Data Catalog のきめ細かい読み取り」のロールからグループまたはユーザーを削除しても、24 時間のキャッシュ保存は無効になりません。「Data Catalog のきめ細かい読み取り」アクセス コントロール グループへの変更はすぐに反映されますが、変更によってキャッシュが無効になることはありません。

ユーザーがクエリを実行しても、クエリ結果は画面に表示されたままになります。また、過去 24 時間以内にデータにアクセスできなくなった場合でも、キャッシュから結果を取得できます。

ユーザーがポリシータグの「Data Catalog のきめ細かい読み取り」のロールから削除されてから 24 時間は、以前に表示が許可されたデータのキャッシュ データにアクセスできます。行がテーブルに追加されると、結果がキャッシュに保存されても、追加された行は表示されません。