使用缓存的查询结果

本文档介绍如何在 BigQuery 中使用缓存结果。

概览

BigQuery 将所有查询结果写入表中。该表可由用户明确标识(目标表),也可以是临时的缓存结果表。临时的缓存结果表按每个用户、每个项目进行维护。使用临时表不会产生任何存储费用,但如果您将查询结果写入永久表,则要支付存储这些数据的费用。

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

限制

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

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

价格和配额

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

查询缓存的例外情况

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

  • 在作业配置、GCP Console、经典版网页界面、命令行或 API 中指定目标表时
  • 自结果上次缓存之后,其引用的表或逻辑视图有任何更改
  • 查询引用的任何表最近收到了流式插入(信息流缓冲区附加到表),即使没有新增任何行
  • 查询使用非确定性函数;例如,日期和时间函数(如 CURRENT_TIMESTAMP()NOW())以及其他函数(如 CURRENT_USER())会根据查询执行的时间返回不同的值
  • 使用通配符查询多个表
  • 缓存结果已过期;一般缓存有效期为 24 小时,但缓存结果均属尽力而为,因此可能会更快失效
  • 查询针对外部数据源运行

缓存结果的存储方式

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

创建匿名数据集时,系统将为运行查询作业的用户明确授予对匿名数据集的 OWNER 访问权限。只有运行查询作业的用户在获得 OWNER 访问权限后才能完全控制数据集,包括对匿名数据集中的缓存结果表的完整控制权。如果您打算共享查询结果,请勿使用存储在匿名数据集中的缓存结果。正确的做法是将结果写入指定的目标表中。

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

匿名数据集的名称以下划线开头。这样会使匿名数据集不出现在 BigQuery 网页界面的数据集列表中。您可以使用 CLI 或 API 列出匿名数据集并审核匿名数据集的访问权限控制。

禁止检索缓存的结果

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

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

如果您要禁止检索缓存的结果,并强制实时评估查询作业,您可以将查询作业的 configuration.query.useQueryCache 属性设置为 false

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

Console

  1. 在 GCP Console 中打开 BigQuery Web 界面。
    转到 BigQuery 网页界面

  2. 点击编写新查询

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

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

    查询设置

  5. 缓存偏好设置下,取消选中使用缓存的结果

    缓存的结果

经典版界面

  1. 转到经典版 BigQuery 网页界面。
    转到 BigQuery 网页界面

  2. 点击 Compose query 按钮。

  3. New Query 文本区域中输入有效的 BigQuery SQL 查询。

  4. 点击 Show Options

  5. 取消选中 Use Cached Results

命令行

使用 nouse_cache 标志覆盖查询缓存。以下示例强制 BigQuery 在不使用现有缓存结果的情况下处理查询:

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

API

要在不使用现有缓存结果的情况下处理查询,请将 useQueryCache 属性设置为 false

Go

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

// To run this sample, you will need to create (or reuse) a context and
// an instance of the bigquery client.  For example:
// import "cloud.google.com/go/bigquery"
// ctx := context.Background()
// client, err := bigquery.NewClient(ctx, "your-project-id")

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"
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.Println(row)
}

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 bigqueryClient = 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 bigqueryClient.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));
}
queryDisableCache();

Java

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

要在不使用现有缓存结果的情况下处理查询,请在创建 QueryJobConfiguration 时将使用查询缓存设置为 false

// BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();
String query = "SELECT corpus FROM `bigquery-public-data.samples.shakespeare` GROUP BY corpus;";
QueryJobConfiguration queryConfig =
    QueryJobConfiguration.newBuilder(query)
        // Disable the query cache to force live query evaluation.
        .setUseQueryCache(false)
        .build();

// Print the results.
for (FieldValueList row : bigquery.query(queryConfig).iterateAll()) {
  for (FieldValue val : row) {
    System.out.printf("%s,", val.toString());
  }
  System.out.printf("\n");
}

Python

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

# from google.cloud import bigquery
# client = bigquery.Client()

job_config = bigquery.QueryJobConfig()
job_config.use_query_cache = False
sql = """
    SELECT corpus
    FROM `bigquery-public-data.samples.shakespeare`
    GROUP BY corpus;
"""
query_job = client.query(
    sql,
    # Location must match that of the dataset(s) referenced in the query.
    location="US",
    job_config=job_config,
)  # API request

# Print the results.
for row in query_job:  # API request - fetches results
    print(row)

确保使用缓存

如果您使用 jobs.insert() 函数运行查询,则可以强制查询作业在缓存结果无法使用的情况下失败,只需将作业配置的 createDisposition 属性设置为 CREATE_NEVER 即可。

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

验证使用缓存

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

  • 如果使用 GCP Console 或经典版 BigQuery 网页界面,那么结果字符串不包含已处理的字节数的相关信息,并显示“cached”一词。

    界面中的缓存指标

  • 如果您使用的是 BigQuery API,那么查询结果中的 cacheHit 属性设置为 true

此页内容是否有用?请给出您的反馈和评价:

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面