估算和控制费用

本页面介绍了如何估算费用,并列出了在 BigQuery 中控制费用的最佳做法。BigQuery 提供两种类型的价格模式:按需价格基于容量的价格。如需了解价格,请参阅 BigQuery 价格

借助 BigQuery,您可以估算运行查询的费用、计算各种查询处理的字节数,并根据预计使用量获取每月费用估算。如需控制费用,您还必须遵循优化查询计算BigQuery 存储的最佳实践。如需了解特定于费用的最佳做法,请参阅控制查询费用

如需监控查询费用和 BigQuery 使用情况,请分析 BigQuery 审核日志

估算查询费用

BigQuery 提供了多种估算费用的方法:

按需查询大小计算

如需使用按需结算模式计算各种类型的查询处理的字节数,请参阅以下部分:

查询 Cloud Storage 中的列式格式

如果外部数据存储在 ORC 或 Parquet 中,则您只需为 BigQuery 读取的列中的字节数付费。由于查询会将来自外部数据源的数据类型转换为 BigQuery 数据类型,因此读取的字节数将根据 BigQuery 数据类型的大小来计算。如需了解数据类型转换,请参阅以下页面:

使用 Google Cloud 价格计算器

Google Cloud 价格计算器可以帮助您根据预计的用量来为 BigQuery 创建总体的每月估算费用。

按需学习

使用按需价格模式时,如需在 Google Cloud 价格计算器中估算费用,请按照以下步骤操作:

  1. 打开 Google Cloud 价格计算器
  2. 点击“BigQuery”。
  3. 点击按需标签页。
  4. 对于表名称,输入表的名称。例如 airports
  5. Storage Pricing(存储价格)部分的存储字段中输入表的估算大小。您只需要估算物理存储空间或逻辑存储空间,具体取决于数据集存储结算模式
  6. Query Pricing(查询价格)部分,输入通过试运行或查询验证器估算的读取字节数。
  7. 点击添加到估算值 (Add To Estimate)。
  8. 估算值会显示在右侧。请注意,您可以保存估算值,也可以通过电子邮件发送估算值。

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

版本

将基于容量的价格模式与 BigQuery 版本搭配使用时,如需在 Google Cloud 价格计算器中估算费用,请按照以下步骤操作:

  1. 打开 Google Cloud 价格计算器
  2. 点击“BigQuery”。
  3. 点击版本标签页。
  4. 选择槽的使用位置。
  5. 选择您的版本
  6. 选择槽数上限基准槽数、可选的承诺Estimated utilization of autoscaling(估算的自动扩缩利用率)。
  7. 选择数据的存储位置。
  8. 输入 Active storage(活跃存储空间)、Long-term storage(长期存储空间)、Streaming inserts(流式插入)和 Streaming reads(流式读取)的存储空间用量的估算值。 您只需要估算物理存储空间或逻辑存储空间,具体取决于数据集存储结算模式
  9. 点击添加到估算

如需了解详情,请参阅基于容量的价格

控制查询费用

如需优化查询费用,请确保您拥有优化的存储空间查询计算。如需了解控制查询费用的其他方法,请参阅以下部分:

在运行之前检查查询费用

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

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

使用查询验证器

在 Google Cloud 控制台中输入查询时,查询验证器会验证查询语法并估算读取的字节数。有了此估算值,您便可在价格计算器中计算查询费用。

  • 如果查询无效,则查询验证器会显示错误消息。例如:

    Not found: Table myProject:myDataset.myTable was not found in location US

  • 如果查询有效,则查询验证器会估算处理查询所需的字节数。例如:

    This query will process 623.1 KiB when run.

执行试运行

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

控制台

  1. 转到 BigQuery 页面。

    转到 BigQuery

  2. 在查询编辑器中输入查询。

    如果查询有效,则会自动显示一个对勾标记以及查询将处理的数据量。如果查询无效,则会显示一个感叹号,并会显示错误消息。

bq

使用 --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 执行试运行,请提交一项查询作业,并在 JobConfiguration 类型中将 dryRun 设置为 true

Go

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

如需向 BigQuery 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证

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)
	}
	defer client.Close()

	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 := status.Err(); err != nil {
		return err
	}
	fmt.Fprintf(w, "This query will process %d bytes\n", status.Statistics.TotalBytesProcessed)
	return nil
}

Java

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

如需向 BigQuery 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.Job;
import com.google.cloud.bigquery.JobInfo;
import com.google.cloud.bigquery.JobStatistics;
import com.google.cloud.bigquery.QueryJobConfiguration;

// Sample to run dry query on the table
public class QueryDryRun {

  public static void runQueryDryRun() {
    String query =
        "SELECT name, COUNT(*) as name_count "
            + "FROM `bigquery-public-data.usa_names.usa_1910_2013` "
            + "WHERE state = 'WA' "
            + "GROUP BY name";
    queryDryRun(query);
  }

  public static void queryDryRun(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).setDryRun(true).setUseQueryCache(false).build();

      Job job = bigquery.create(JobInfo.of(queryConfig));
      JobStatistics.QueryStatistics statistics = job.getStatistics();

      System.out.println(
          "Query dry run performed successfully." + statistics.getTotalBytesProcessed());
    } catch (BigQueryException 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');
const bigquery = new BigQuery();

async function queryDryRun() {
  // Runs a dry query of the U.S. given names dataset for the state of Texas.

  const query = `SELECT name
    FROM \`bigquery-public-data.usa_names.usa_1910_2013\`
    WHERE state = 'TX'
    LIMIT 100`;

  // For all options, see https://cloud.google.com/bigquery/docs/reference/rest/v2/jobs/query
  const options = {
    query: query,
    // Location must match that of the dataset(s) referenced in the query.
    location: 'US',
    dryRun: true,
  };

  // Run the query as a job
  const [job] = await bigquery.createQueryJob(options);

  // Print the status and statistics
  console.log('Status:');
  console.log(job.metadata.status);
  console.log('\nJob Statistics:');
  console.log(job.metadata.statistics);
}

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);
$jobConfig->dryRun(true);

// Extract query results
$queryJob = $bigQuery->startJob($jobConfig);
$info = $queryJob->info();

printf('This query will process %s bytes' . PHP_EOL, $info['statistics']['totalBytesProcessed']);

Python

QueryJobConfig.dry_run 属性设置为 True。如果提供了试运行查询配置,Client.query() 将始终返回已完成的 QueryJob

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

如需向 BigQuery 进行身份验证,请设置应用默认凭据。 如需了解详情,请参阅为本地开发环境设置身份验证

from google.cloud import bigquery

# 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))

避免运行查询来探索表数据

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

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

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

  • 在 Google Cloud 控制台中的表详情页面上,点击预览标签页以对数据进行采样。
  • 在 bp 命令行工具中,使用 bq head 命令并指定要预览的行数。
  • 在 API 中,使用 tabledata.list 从一组指定的行中检索表数据。

限制结算的字节数

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

您可以使用结算字节数上限设置来限制对查询结算的字节数。设置结算字节数上限时,将在执行查询之前估算查询将读取的字节数。如果估算的字节数超过了限制,则查询会失败,但不会产生费用。

对于聚簇表,对查询计费的字节数估算值为上限,可能会高于运行查询后实际计费的字节数。因此,在某些情况下,如果设置了结算字节数上限,则对聚簇表运行的查询可能会失败,即使实际结算的字节数不会超过结算字节数上限设置也不例外。

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

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

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

控制台

  1. 查询编辑器中,点击更多 > 查询设置 > 高级选项
  2. 结算字节数上限字段中,输入一个整数。
  3. 点击保存

bq

使用带有 --maximum_bytes_billed 标志的 bq query 命令。

  bq query --maximum_bytes_billed=1000000 \
  --use_legacy_sql=false \
  'SELECT
     word
   FROM
     `bigquery-public-data`.samples.shakespeare'

API

JobConfigurationQueryQueryRequest 中设置 maximumBytesBilled 属性。

避免在非聚簇表中使用 LIMIT

最佳做法:对于非聚簇表,请勿使用 LIMIT 子句控制费用。

对于非聚簇表,对查询应用 LIMIT 子句不会影响读取的数据量。您需要支付读取查询所指示整个表中的所有字节而产生的费用,即使该查询仅返回子集。对于聚簇表,LIMIT 子句可以减少扫描的字节数,因为扫描足够多的块来获取结果后会停止扫描。您只需为扫描的字节数付费。

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

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

您可以导出结算数据到 BigQuery,并在 Looker 数据洞察等工具中直观呈现这些数据。如需查看有关如何创建结算信息中心的教程,请参阅使用 BigQuery 和 Looker Studio 直观呈现 Google Cloud 结算信息

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

分阶段将查询结果具体化

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

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

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

使用目标表的表过期时间

最佳做法:如果要将大量查询结果写入目标表,请使用默认表过期时间移除不再需要的数据。

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

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

后续步骤