使用缓存的查询结果

BigQuery 将所有查询结果写入表中。该表可由用户明确标识(目标表),也可以是临时的缓存结果表。如果您再次运行完全相同的查询,BigQuery 会从缓存表(如果存在)中返回结果。临时的缓存结果表按每个用户、每个项目进行维护。根据您的版本,您可能有权访问在同一项目中运行查询的其他用户的缓存结果。缓存的查询结果表不会产生任何存储费用,但如果您将查询结果写入永久表,则需要支付这些数据的存储费用。

所有查询结果(包括交互式查询和批量查询)都会在临时表中缓存大约 24 小时,但有一些例外情况

限制

使用查询缓存时,会受到以下限制:

  • 当您运行重复的查询时,BigQuery 会尝试重复使用缓存结果。如需从缓存中检索数据,重复查询文本必须与原始查询相同。
  • 要使查询结果保留在缓存结果表中,结果集必须小于响应大小上限。如需详细了解如何管理大型结果集,请参阅返回大查询结果
  • 在使用 DML 语句时,不能将缓存结果表指定为目标表。
  • 尽管当前语义允许,但强烈建议您不要将缓存结果用作从属作业的输入。例如,不应提交从缓存表中检索结果的查询作业,而是应该将结果写入已命名的目标表中。为简化清理,数据集级层 defaultTableExpirationMs 属性等功能可以在给定期限后自动使数据过期。

价格和配额

缓存的查询结果存储为临时表。您不需要为临时表中的缓存查询结果支付存储费用。如果查询结果是从缓存结果表中检索到的,则作业统计信息属性 statistics.query.cacheHit 将返回 true 值,您无需为该查询支付费用。虽然使用缓存结果的查询不会产生费用,但这些查询仍受 BigQuery 配额政策约束。除了降低费用之外,使用缓存结果的查询速度明显更快,因为 BigQuery 不需要计算结果集。

查询缓存的例外情况

在以下情况下,查询结果将无法缓存:

  • 您在作业配置、Google Cloud 控制台、bq 命令行工具或 API 中指定了目标表。
  • 自结果上次缓存之后,其引用的表或逻辑视图有任何更改。
  • 查询引用的任何表最近收到了流式插入内容(表中包含写入优化存储空间中的数据),即使没有新增任何行。
  • 如果查询使用非确定性函数;例如,日期和时间函数(如 CURRENT_TIMESTAMP()CURRENT_DATE)以及其他函数(如 SESSION_USER()),则会根据查询执行时间返回不同的值。
  • 使用通配符查询多个表。
  • 缓存结果已过期;一般缓存有效期为 24 小时,但缓存结果均属尽力而为,因此可能会更快失效。
  • 查询针对 Cloud Storage 以外的外部数据源运行。(缓存的查询结果支持 Cloud Storage 上的 GoogleSQL 查询。)
  • 如果查询针对受列级安全性保护的表运行,则结果可能无法缓存。
  • 如果查询针对受行级安全性保护的表运行,则系统不会缓存结果。

缓存结果的存储方式

运行查询时,系统会在一种特殊类型的隐藏数据集(称为“匿名数据集”)中创建临时缓存结果表。与从 IAM 资源层次结构模型(项目和组织权限)继承权限的常规数据集不同,只有数据集所有者能够访问匿名数据集。匿名数据集的所有者就是运行查询生成了缓存结果的用户。此外,系统还会检查项目的 bigquery.jobs.create 权限,以验证用户是否有权访问项目。

BigQuery 不支持共享匿名数据集。如果您打算共享查询结果,请勿使用存储在匿名数据集中的缓存结果。正确的做法是将结果写入已命名的目标表中。

虽然运行该查询的用户具有对数据集和缓存结果表的完整访问权限,但建议您不要将其用作从属作业的输入。

匿名数据集的名称以下划线开头。因此,Google Cloud 控制台中的数据集列表中不会显示这些信息。您可以使用 bq 命令行工具或 API 列出匿名数据集并审核匿名数据集的访问权限控制。

如需详细了解如何列出和获取数据集(包括匿名数据集)的相关信息,请参阅列出数据集

跨用户缓存

如果您使用的是企业或企业 Plus 版本,并且拥有为另一个用户执行在您的项目中缓存的查询所需的权限,则 BigQuery 会生成缓存结果。缓存结果会复制到您的个人匿名数据集中,并在运行查询后保留 24 小时。单用户缓存的限制和例外情况同样适用于跨用户缓存。

停用缓存结果检索功能

当您选中使用缓存的结果选项后,除非查询的表已更改,否则您可以重复利用之前运行的相同查询的结果。使用缓存的结果仅对重复查询有利。对于新查询,使用缓存的结果选项虽然默认为启用,但没有任何效果。

当您在已停用使用缓存的结果选项的情况下重复查询时,将覆盖现有的缓存结果。这会要求 BigQuery 来计算查询结果,因此将向您收取该查询的费用。这在基准化分析场景中尤其有用。

如果您要停用缓存结果检索功能并强制对查询作业进行实时评估,可以将查询作业的 configuration.query.useQueryCache 属性设置为 false

要停用使用缓存的结果选项,请执行以下操作:

控制台

  1. 打开 Google Cloud 控制台。
    转到 BigQuery 页面

  2. 点击编写新查询

  3. 查询编辑器文本区域中输入有效的 SQL 查询。

  4. 点击更多,然后选择查询设置

    查询设置

  5. 缓存偏好设置部分,清除使用缓存的结果

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 参考文档

如需向 BigQuery 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为客户端库设置身份验证

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 时,将 set use query cache 设为 false

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 参考文档

如需向 BigQuery 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为客户端库设置身份验证

// 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));
}

PHP

试用此示例之前,请按照 BigQuery 快速入门:使用客户端库中的 PHP 设置说明进行操作。如需了解详情,请参阅 BigQuery PHP API 参考文档

如需向 BigQuery 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为客户端库设置身份验证

use Google\Cloud\BigQuery\BigQueryClient;

/** Uncomment and populate these variables in your code */
// $projectId = 'The Google project ID';
// $query = 'SELECT id, view_count FROM `bigquery-public-data.stackoverflow.posts_questions`';

// Construct a BigQuery client object.
$bigQuery = new BigQueryClient([
    'projectId' => $projectId,
]);

// Set job configs
$jobConfig = $bigQuery->query($query);
$jobConfig->useQueryCache(false);

// Extract query results
$queryResults = $bigQuery->runQuery($jobConfig);

$i = 0;
foreach ($queryResults as $row) {
    printf('--- Row %s ---' . PHP_EOL, ++$i);
    foreach ($row as $column => $value) {
        printf('%s: %s' . PHP_EOL, $column, json_encode($value));
    }
}
printf('Found %s row(s)' . PHP_EOL, $i);

Python

试用此示例之前,请按照 BigQuery 快速入门:使用客户端库中的 Python 设置说明进行操作。如需了解详情,请参阅 BigQuery Python API 参考文档

如需向 BigQuery 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为客户端库设置身份验证

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 方法运行查询,则可以通过将 query 作业配置的 createDisposition 属性设置为 CREATE_NEVER,强制使无法使用缓存结果的查询作业返回失败。

如果缓存中不存在查询结果,系统会返回 NOT_FOUND 错误。

bq

使用 --require_cache 标志以要求使用查询缓存中的结果。以下示例会在结果存在于缓存中时强制 BigQuery 处理查询:

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

API

如需使用现有缓存结果处理查询,请在 query 作业配置中将 createDisposition 属性设置为 CREATE_NEVER

验证使用缓存

您可以通过以下两种方式确定 BigQuery 是否使用缓存返回结果:

  • 使用 Google Cloud 控制台。转到查询结果,然后点击作业信息处理的字节数显示 0 B(缓存的结果)
  • 使用 BigQuery API 查询结果中的 cacheHit 属性设置为 true

列级别安全性的影响

默认情况下,除上述例外情况以外,BigQuery 会将查询结果缓存 24 小时。针对受列级别安全性保护的表的查询可能不会被缓存。如果 BigQuery 缓存了结果,则 24 小时缓存有效期适用。

某些更改(例如将某个群组或用户从用于政策标记的 Data Catalog Fine Grained Reader 角色中移除)不会导致 24 小时缓存功能失效。对 Data Catalog Fine Grained Reader 访问权限控制组本身进行的更改会立即传播,但该更改不会使缓存失效。

由此产生的影响是,如果用户运行了查询,则该用户仍然可以在屏幕上看到查询结果。即使该用户在过去 24 小时内无法访问数据,也可以从缓存中检索这些结果。

在用户从用于政策标记的 Data Catalog Fine Grained Reader 角色中被移除后的 24 小时内,该用户只能访问其之前可查看的数据的缓存数据。如果表中添加了行,那么即使缓存了结果,用户也无法看到所添加的行。