管理分区表

本文档介绍了如何在 BigQuery 中管理分区表。

获取分区元数据

您可以通过以下方式来获取有关分区表的信息:

使用 INFORMATION_SCHEMA 视图获取分区元数据

当您查询 INFORMATION_SCHEMA.PARTITIONS 视图时,每个分区都会有一行对应的查询结果。例如,以下查询列出了名为 mydataset 的数据集中的所有表分区:

SELECT table_name, partition_id, total_rows
FROM `mydataset.INFORMATION_SCHEMA.PARTITIONS`
WHERE partition_id IS NOT NULL

如需了解详情,请参阅 INFORMATION_SCHEMA.PARTITIONS

使用元表获取分区元数据

在旧版 SQL 中,您可以通过查询 __PARTITIONS_SUMMARY__ 元表来获取表分区的元数据。元表是包含元数据的只读表。

按如下方式查询 __PARTITIONS_SUMMARY__ 元表:

#legacySQL
SELECT
  column
FROM
  [dataset.table$__PARTITIONS_SUMMARY__]

__PARTITIONS_SUMMARY__ 元表具有以下列:

说明
project_id 项目名称。
dataset_id 数据集名称。
table_id 时间分区表的名称。
partition_id 分区的名称(日期)。
creation_time 创建分区的时间,以从 UTC 1970 年 1 月 1 日起计算的毫秒数表示。
last_modified_time 上次修改分区的时间,以从 UTC 1970 年 1 月 1 日起计算的毫秒数表示。

如需运行使用 __PARTITIONS_SUMMARY__ 元表的查询作业,您至少必须具有 bigquery.jobs.create 权限和 bigquery.tables.getData 权限。

要详细了解 BigQuery 中的 IAM 角色,请参阅访问权限控制

设置分区过失效时间

当您创建按注入时间或时间单位列分区的表时,可以指定分区过期时间。此设置指定 BigQuery 在每个分区中保留数据的时长。该设置适用于表中的所有分区,但系统会根据分区时间独立计算每个分区的设置。

分区的到期时间根据分区边界(采用世界协调时间 (UTC))计算。例如,对于每日分区,分区边界在午夜零点(00:00:00 UTC)开始。如果表的分区到期时间为 6 小时,则每个分区将在次日 06:00:00 UTC 到期。 分区过期后,BigQuery 将删除该分区中的数据。

您还可以在数据集级层指定默认分区到期时间。如果您为表设置了分区到期时间,则该值会替换默认分区到期时间。如果未指定任何分区到期时间(表或数据集),则分区将永不过期。

如果您设置了表到期时间,则该值优先于分区到期时间。例如,如果表到时间设置为 5 天,分区到期时间设置为 7 天,则该表及其所含的所有分区都将在 5 天后删除。

表创建完毕后,您可以随时更新表的分区到期时间。新设置将应用于该表中的所有分区,无论这些分区是何时创建的。如果现有分区早于新的到期时间,则会立即过期。 同样,如果数据被复制或插入到按时间单位列划分的表中,则任何早于为该表配置的分区过期时间的分区都会立即过期。

分区过期后,BigQuery 会删除该分区。分区数据会根据时间旅行故障安全政策进行保留,并且可能会产生费用,具体取决于您的结算模式。在此之前,分区将计入表配额。如需立即删除分区,您可以手动删除分区

更新分区过失效时间

要更新分区表的分区过期时间,请按如下所述操作:

控制台

您无法在 Google Cloud 控制台中更新分区到期时间。

SQL

使用 ALTER TABLE SET OPTIONS 语句。以下示例会将到期时间更新为 5 天。要移除表的分区到期时间,请将 partition_expiration_days 设置为 NULL

  1. 在 Google Cloud 控制台中,转到 BigQuery 页面。

    转到 BigQuery

  2. 在查询编辑器中,输入以下语句:

    ALTER TABLE mydataset.mytable
      SET OPTIONS (
        -- Sets partition expiration to 5 days
        partition_expiration_days = 5);

  3. 点击 运行

如需详细了解如何运行查询,请参阅运行交互式查询

bq

发出带 --time_partitioning_expiration 标志的 bq update 命令。如果您要更新非默认项目中的分区表,请按以下格式将相应项目 ID 添加到数据集名称中:project_id:dataset

bq update \
--time_partitioning_expiration integer_in_seconds \
--time_partitioning_type unit_time \
project_id:dataset.table

其中:

  • integer 是表分区的默认生命周期(以秒为单位)。它没有最小值。过期时间以分区的日期加上这个整数值为准。如果您指定了 0,则分区过期时间将被移除,且分区永不过期。您必须手动删除没有过期时间的分区。
  • unit_timeDAYHOURMONTHYEAR,具体取决于表的分区粒度。此值必须与您在创建表时设置的粒度一致。
  • project_id 是项目 ID。
  • dataset 是要更新的表所属的数据集的名称。
  • table 是要更新的表的名称。

示例:

输入以下命令可将 mydataset.mytable 中分区的过期时间更新为 5 天(432000 秒)。mydataset 属于默认项目。

bq update --time_partitioning_expiration 432000 mydataset.mytable

输入以下命令可将 mydataset.mytable 中分区的过期时间更新为 5 天(432000 秒)。mydataset 属于 myotherproject,而非默认项目。

bq update \
--time_partitioning_expiration 432000 \
myotherproject:mydataset.mytable

API

调用 tables.patch 方法,并使用 timePartitioning.expirationMs 属性更新分区过期时间(以毫秒为单位)。由于 tables.update 方法会替换整个表资源,因此建议使用 tables.patch 方法。

设置分区过滤条件要求

创建分区表时,您可以要求表上的所有查询都必须包含用于过滤分区列的谓词过滤条件(WHERE 子句)。此设置可以提高性能并降低费用,因为 BigQuery 可以使用过滤条件来删减与谓词不匹配的分区。

如需了解如何在创建分区表时添加需要分区过滤条件选项,请参阅创建分区表

如果分区表具有需要分区过滤条件设置,则该表上的每个查询都必须包含至少一个仅引用分区列的谓词。不含此类谓词的查询会返回以下错误:

Cannot query over table 'project_id.dataset.table' without a filter that can be used for partition elimination

如需了解详情,请参阅查询分区表

更新分区过滤条件要求

如果在创建分区表时未启用需要分区过滤条件选项,您可以更新表来添加该选项。

控制台

创建分区表后,您无法使用 Google Cloud 控制台来要求启用分区过滤条件。

SQL

使用 ALTER TABLE SET OPTIONS 语句更新分区过滤条件要求。以下示例将要求更新为 true

  1. 在 Google Cloud 控制台中,转到 BigQuery 页面。

    转到 BigQuery

  2. 在查询编辑器中,输入以下语句:

    ALTER TABLE mydataset.mypartitionedtable
      SET OPTIONS (
        require_partition_filter = true);

  3. 点击 运行

如需详细了解如何运行查询,请参阅运行交互式查询

bq

如需使用 bq 命令行工具更新分区表以要求启用分区过滤条件,请输入 bq update 命令并提供 --require_partition_filter 标志。

如需在非默认项目中更新分区表,请按以下格式将相应项目 ID 添加到数据集内:project_id:dataset

例如:

如需更新默认项目中 mydatasetmypartitionedtable,请输入以下命令:

bq update --require_partition_filter mydataset.mytable

如需更新 myotherprojectmydatasetmypartitionedtable,请输入以下命令:

bq update --require_partition_filter myotherproject:mydataset.mytable

API

调用 tables.patch 方法,并将 requirePartitionFilter 属性设置为 true 以要求启用分区过滤条件。由于 tables.update 方法会替换整个表资源,因此建议使用 tables.patch 方法。

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.Table;

// Sample to update require partition filter on a table.
public class UpdateTableRequirePartitionFilter {

  public static void runUpdateTableRequirePartitionFilter() {
    // TODO(developer): Replace these variables before running the sample.
    String datasetName = "MY_DATASET_NAME";
    String tableName = "MY_TABLE_NAME";
    updateTableRequirePartitionFilter(datasetName, tableName);
  }

  public static void updateTableRequirePartitionFilter(String datasetName, String tableName) {
    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();

      Table table = bigquery.getTable(datasetName, tableName);
      table.toBuilder().setRequirePartitionFilter(true).build().update();

      System.out.println("Table require partition filter updated successfully");
    } catch (BigQueryException e) {
      System.out.println("Table require partition filter was not updated \n" + e.toString());
    }
  }
}

复制分区表

复制分区表的过程与复制标准表的过程相同。如需了解详情,请参阅复制表

复制分区表时,请注意以下事项:

  • 将分区表复制到新的目标表
    所有分区信息都会随该表一起复制。新表和旧表将具有相同的分区。
  • 将非分区表复制到现有分区表
    此操作仅支持提取时间分区。BigQuery 会将源数据复制到表示当前日期的分区。时间单位列分区表或整数范围分区表不支持此操作。
  • 将一个分区表复制到另一个分区表
    源表和目标表的分区规范必须匹配。
  • 将分区表复制到非分区表
    目标表保持未分区状态。
  • 复制多个分区表

    如果将多个源表复制到同一作业中的某个分区表,则源表不能同时包含分区表和非分区表。

    如果所有源表都是分区表,则所有源表的分区规范必须与目标表的分区规范匹配。

复制到现有表时,您可以指定是附加到目标表还是覆盖目标表。

复制各个分区

您可以将一个或多个分区中的数据复制到另一个表。

控制台

Google Cloud 控制台不支持复制分区。

bq

如需复制分区,请使用 bq 命令行工具的 bq cp(复制)命令和分区修饰器 ($date),例如 $20160201

可使用以下可选标志来控制目标分区的写入处置方式:

  • -a--append_table:用于将源分区中的数据附加到目标数据集中的现有表或分区。
  • -f--force:用于覆盖目标数据集中的现有表或分区,并且不会提示您进行确认。
  • -n--no_clobber:用于在目标数据集中已存在同名表或分区时返回以下错误消息:Table '<var>project_id:dataset.table</var> or <var>table$date</var>' already exists, skipping.。如果未指定 -n,则默认行为是提示您选择是否替换目标表或分区。
  • --destination_kms_key 是客户管理的 Cloud KMS 密钥,用于加密目标表或分区。

cp 命令不支持 --time_partitioning_field--time_partitioning_type 标志。您不能使用复制作业将提取时间分区表转换为分区表。

本文未演示 --destination_kms_key。如需了解详情,请参阅使用 Cloud KMS 密钥保护数据

如果源数据集或目标数据集属于非默认项目,请按以下格式将相应项目 ID 添加到数据集名称中:project_id:dataset

(可选)提供 --location 标志并将其值设置为您的位置

bq --location=location cp \
-a -f -n \
project_id:dataset.source_table$source_partition \
project_id:dataset.destination_table$destination_partition

其中:

  • location 是位置的名称。--location 是可选标志。例如,如果您在东京区域使用 BigQuery,可将该标志的值设置为 asia-northeast1。您可以使用 .bigqueryrc 文件设置该位置的默认值。
  • project_id 是项目 ID。
  • dataset 是源数据集或目标数据集的名称。
  • source_table 是要复制的表。
  • source_partition 是源分区的分区修饰器。
  • destination_table 是目标数据集中表的名称。
  • destination_partition 是目标分区的分区修饰器。

示例:

将分区复制到新表

输入以下命令可将 mydataset.mytable 中与 2018 年 1 月 30 日对应的分区复制到新表 mydataset.mytable2mydataset 属于默认项目。

bq cp -a 'mydataset.mytable$20180130' mydataset.mytable2

将分区复制到非分区表

输入以下命令可将 mydataset.mytable 中与 2018 年 1 月 30 日对应的分区复制到非分区表 mydataset2.mytable2。使用 -a 快捷方式可将该分区的数据附加到非分区目标表。两个数据集均属于您的默认项目。

bq cp -a 'mydataset.mytable$20180130' mydataset2.mytable2

输入以下命令可将 mydataset.mytable 中与 2018 年 1 月 30 日对应的分区复制到非分区表 mydataset2.mytable2。使用 -f 快捷方式可在无提示的情况下覆盖非分区目标表。

bq --location=US cp -f 'mydataset.mytable$20180130' mydataset2.mytable2

将分区复制到其他分区表

输入以下命令可将 mydataset.mytable 中与 2018 年 1 月 30 日对应的分区复制到另一个分区表 mydataset2.mytable2。使用 -a 快捷方式可将该分区的数据附加到目标表。由于没有为目标表指定分区修饰器,因此源分区键会被保留,并且数据将被复制到目标表中与 2018 年 1 月 30 日对应的分区。您还可以为目标表指定分区修饰器,以将数据复制到特定分区。mydataset 属于默认项目。mydataset2 属于 myotherproject,而非默认项目。

bq --location=US cp \
-a \
'mydataset.mytable$20180130' \
myotherproject:mydataset2.mytable2

输入以下命令可将 mydataset.mytable 中与 2018 年 1 月 30 日对应的分区复制到另一个分区表 mydataset2.mytable2 中与 2018 年 1 月 30 日对应的分区。使用 -f 快捷方式可在无提示的情况下覆盖目标表中与 2018 年 1 月 30 日对应的分区。如果未使用分区修饰器,则目标表中的所有数据都会被覆盖。mydataset 属于默认项目。 mydataset2 属于 myotherproject,而非默认项目。

bq cp \
-f \
'mydataset.mytable$20180130' \
'myotherproject:mydataset2.mytable2$20180130'

输入以下命令可将 mydataset.mytable 中与 2018 年 1 月 30 日对应的分区复制到另一个分区表 mydataset2.mytable2mydataset 属于默认项目。mydataset2 属于 myotherproject,而非默认项目。如果目标表中存在数据,则默认情况下,系统会提示您覆盖这些数据。

bq cp \
'mydataset.mytable$20180130' \
myotherproject:mydataset2.mytable2

如需复制多个分区,请以英文逗号分隔列表的形式指定这些分区:

bq cp \
'mydataset.mytable$20180130,mydataset.mytable$20180131' \
myotherproject:mydataset.mytable2

API

调用 jobs.insert 方法并配置 copy 作业。(可选)在作业资源 jobReference 部分的 location 属性中指定您的区域。

在作业配置中指定以下属性:

  • sourceTables 属性中输入源数据集、表和分区。
  • destinationTable 属性中输入目标数据集和表。
  • 使用 writeDisposition 属性指定是将数据附加到目标表或分区还是进行覆盖。

如需复制多个分区,请在 sourceTables 属性中输入源分区(包括数据集和表名称)。

删除分区

您可以从分区表中删除个别分区。但是,您无法删除特殊的 __NULL____UNPARTITIONED__ 分区。

您一次只能删除一个分区。

如需删除某一分区,您可以指定分区的修饰器,除非该分区是两种特殊分区之一。

如需删除分区表中的某一分区,请按如下所述操作:

控制台

Google Cloud 控制台不支持删除分区。

SQL

如果符合条件的 DELETE 语句涵盖分区中的所有行,则 BigQuery 将移除整个分区。此移除操作不需要扫描字节或使用槽。以下 DELETE 语句示例涵盖 _PARTITIONDATE 伪列上的过滤器的整个分区:

  1. 在 Google Cloud 控制台中,转到 BigQuery 页面。

    转到 BigQuery

  2. 在查询编辑器中,输入以下语句:

    DELETE mydataset.mytable
    WHERE _PARTITIONDATE IN ('2076-10-07', '2076-03-06');

  3. 点击 运行

如需详细了解如何运行查询,请参阅运行交互式查询

bq

使用带有 --table 标志(或 -t 快捷方式)的 bq rm 命令,并指定分区修饰器以删除特定分区。

bq rm --table project_id:dataset.table$partition

其中:

  • project_id 是项目 ID。如果省略,则系统会使用默认项目。
  • dataset 是包含表的数据集的名称。
  • table 是表的名称。
  • partition 是您要删除的分区的分区修饰器。

分区修饰器具有以下格式(具体取决于分区类型):

  • 每小时分区:yyyymmddhh。示例:$2016030100
  • 每日分区:yyyymmdd。示例:$20160301
  • 每月分区:yyyymm。示例:$201603
  • 每年分区:yyyy。示例:$2016
  • 整数范围分区:分区范围的开始。示例:$20

bq 命令行工具会提示您确认操作。如需跳过确认,请使用 --force 标志(或 -f 快捷方式)。

示例:

删除默认项目中名为 mydataset.mytable 的每日分区表中 2016 年 3 月 1 日的分区:

bq rm --table 'mydataset.mytable$20160301'

在每月分区表中删除 2016 年 3 月的分区:

bq rm --table 'mydataset.mytable$201603'

从名为 mydataset.mytable 的整数范围分区表中删除从 20 开始的整数范围:

bq rm --table 'mydataset.mytable$20'

API

调用 tables.delete 方法,并使用 tableId 参数指定表和分区的修饰器。

分区表安全性

分区表的访问权限控制与标准表的访问权限控制相同。如需了解详情,请参阅表访问权限控制简介