BigQuery 最佳做法:控制费用

本页面介绍了在 BigQuery 中控制费用的最佳做法。

避免使用 SELECT *

最佳做法:仅查询所需的列。

使用 SELECT * 查询数据所需的费用最高。当您使用 SELECT * 时,BigQuery 会全面扫描表中的所有列。

如果您要进行数据实验或探索数据,请使用某一数据预览选项,而不要使用 SELECT *

SELECT * 查询应用 LIMIT 子句不会影响读取的数据量。您需要支付读取整个表中的所有字节而产生的费用,并且查询读取的数据量会占用您的免费层级配额。

因此,更好的做法是仅查询所需的列。例如,使用 SELECT * EXCEPT 从结果中排除一列或多列数据。

如果您确实需要查询表中的所有列,但只需要查询部分数据,请考虑使用以下方法:

  • 将查询结果具体化到一个目标表中,然后对该表执行查询
  • 按日期对表进行分区,然后查询相关分区;例如,WHERE _PARTITIONDATE="2017-01-01" 只会扫描与 2017 年 1 月 1 日对应的分区

使用预览选项对数据采样

最佳做法:不要运行查询来探索或预览表数据。

如果您要试验或探索数据,可以使用表预览选项来查看数据,这种方式是免费的而且不会影响配额。

BigQuery 支持以下数据预览选项:

  • 在 Cloud Console 或经典版网页界面中的表详情页面上,点击预览标签页以对数据进行采样。
  • 在 CLI 中,使用 bq head 命令并指定要预览的行数。
  • 在 API 中,使用 tabledata.list 从一组指定的行中检索表数据。

在运行查询之前估算查询费用

最佳做法:在运行查询前,先进行预览以估算相关费用。

我们会根据读取的字节数收取查询费用。如需在运行查询之前估算费用,请使用以下方法:

  • 查看 Cloud Console 或经典版网页界面中的查询验证器
  • 使用 Google Cloud Platform 价格计算器
  • 通过以下方式执行试运行:
    • 使用 CLI 中的 --dry_run 标志
    • 使用 dryRun 参数(通过 API 提交查询作业时)

使用查询验证器

在 Cloud Console 或经典版网页界面中输入查询时,查询验证器会验证查询语法并估算读取的字节数。有了此估算值,您便可在价格计算器中计算查询费用。

查询验证器

执行试运行

如需执行试运行,请执行以下操作:

控制台

目前,您无法使用 Cloud Console 执行试运行。

经典版界面

目前,您无法使用网页界面执行试运行。

CLI

使用 --dry_run 标志输入如下所示的查询。

bq query \
--use_legacy_sql=false \
--dry_run \
'SELECT
   COUNTRY,
   AIRPORT,
   IATA
 FROM
   `project_id`.dataset.airports
 LIMIT
   1000'
 

该命令会产生如下响应:

Query successfully validated. Assuming the tables are not modified,
running this query will process 10918 bytes of data.

API

如需使用 API 执行试运行,请提交一项查询作业,并在作业配置中将 dryRun 设置为 true

Go

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

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/bigquery"
)

// queryDryRun demonstrates issuing a dry run query to validate query structure and
// provide an estimate of the bytes scanned.
func queryDryRun(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)
	}

	q := client.Query(`
	SELECT
		name,
		COUNT(*) as name_count
	FROM ` + "`bigquery-public-data.usa_names.usa_1910_2013`" + `
	WHERE state = 'WA'
	GROUP BY name`)
	q.DryRun = 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
	}
	// Dry run is not asynchronous, so get the latest status and statistics.
	status := job.LastStatus()
	if err != nil {
		return err
	}
	fmt.Fprintf(w, "This query will process %d bytes\n", status.Statistics.TotalBytesProcessed)
	return nil
}

Python

如需使用 Python 客户端库执行试运行,请将 QueryJobConfig.dry_run 属性设置为 True。如果提供了试运行查询配置,Client.query() 将始终返回已完成的 QueryJob

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

from google.cloud import bigquery

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

job_config = bigquery.QueryJobConfig(dry_run=True, use_query_cache=False)

# Start the query, passing in the extra configuration.
query_job = client.query(
    (
        "SELECT name, COUNT(*) as name_count "
        "FROM `bigquery-public-data.usa_names.usa_1910_2013` "
        "WHERE state = 'WA' "
        "GROUP BY name"
    ),
    job_config=job_config,
)  # Make an API request.

# A dry run query completes immediately.
print("This query will process {} bytes.".format(query_job.total_bytes_processed))

使用价格计算器

如需使用 Google Cloud 价格计算器估算查询费用,请输入查询所处理的字节数(以 MB、GB、TB 或 PB 为单位)。如果您的查询处理的数据量不足 1 TB,估算结果就是 $0,因为 BigQuery 每月免费提供 1 TB 的按需查询处理配额。

价格计算器

通过限制结算的字节数来限制查询费用

最佳做法:使用结算字节数上限设置来限制查询费用。

您可以使用结算字节数上限设置来限制对查询结算的字节数。设置结算字节数上限时,如果查询读取的字节数超出此限制,查询将失败,但不会产生费用。

如果查询因结算字节数上限设置而失败,将返回如下错误:

Error: Query exceeded limit for bytes billed: 1000000. 10485760 or higher required.

如需设置结算字节数上限,请按如下所述操作:

  • 在经典版 BigQuery 网页界面中,在查询选项的 Maximum Bytes Billed 字段中输入一个整数。目前,Cloud Console 不支持 结算字节数上限 选项。结算字节数上限
  • 在 CLI 中,搭配使用 bq query 命令和 --maximum_bytes_billed 标志。

    bq query --maximum_bytes_billed=1000000 \
    --use_legacy_sql=false \
    'SELECT
       word
     FROM
       `bigquery-public-data`.samples.shakespeare'
    
  • 通过 API 在 query 作业配置中设置 maximumBytesBilled 属性。

LIMIT 不影响费用

最佳做法:不使用 LIMIT 子句控制费用。

对查询应用 LIMIT 子句不会影响读取的数据量,只会限制结果集输出。您需要支付根据查询的指示读取整个表中的所有字节而产生的费用。

尽管存在 LIMIT 子句,查询读取的数据量仍会占用您的免费层级配额。

使用信息中心查看费用并查询审核日志

最佳做法:创建信息中心来查看结算数据,以便于调整 BigQuery 使用量。此外,还要考虑将审核日志流式插入到 BigQuery,以便分析使用规律。

您可以将结算数据导出到 BigQuery,并在 Google 数据洞察等工具中直观显示该数据。 如需查看关于如何创建结算信息中心的教程,请参阅使用 BigQuery 和 Google 数据洞察直观呈现 GCP 结算信息

此外,您还可以将审核日志流式插入到 BigQuery,并分析日志以了解使用规律(例如用户的查询费用)。

按日期对数据分区

最佳做法:按日期对表进行分区。

如果可能,请尽量按日期对 BigQuery 表进行分区。对表进行分区后,您可以查询相关的数据子集,从而提高性能并降低费用。

例如,在查询分区后的表时,使用 _PARTITIONTIME 伪列针对某一日期或日期范围进行过滤。该查询只会处理相应日期或日期范围所指定分区中的数据。

分阶段将查询结果具体化

最佳做法:如果可能,请分阶段将查询结果具体化。

如果您创建了一个大型的多阶段查询,则每次运行该查询时,BigQuery 都会读取查询所需的所有数据。这样,您就需要支付查询在每次运行时读取的所有数据所产生的费用。

因此,更好的做法是将查询分为多个阶段,并在每个阶段中通过将查询结果写入一个目标表来将这些结果具体化。 查询较小的目标表可减少数据读取量并降低费用。存储具体化结果的费用远低于处理大量数据的费用。

考虑大型结果集的费用

最佳做法:如果您要将大量查询结果写入目标表,请使用默认表过期时间,以便让系统在您不再需要这些数据时将其移除。

将大型结果集保留在 BigQuery 存储空间中会产生费用。如果您不需要永久访问这些结果,请使用默认表过期时间来让系统自动为您删除数据。

如需了解详情,请参阅存储价格

谨慎使用流式数据插入

最佳做法:仅当您需要数据立即可用时,才使用流式数据插入功能。

数据加载到 BigQuery 无需付费。不过,将数据流式插入到 BigQuery 则需要付费。除非您需要数据立即可供使用,否则请加载数据,而不要流式插入数据。