分区表分成多个区段(称为分区),可让你更轻松地管理和查询数据。通过将大型表划分为较小的分区,可以改善查询性能;通过减少查询读取的字节数,可以控制费用。通过指定用于将表分段的分区列来对表进行分区。


如果查询对分区列的值使用符合条件的过滤条件,则 BigQuery 可以扫描与过滤条件匹配的分区并跳过其余分区。此过程称为“删减”。


在分区表中,数据存储在物理块中,而每个物理块都包含一个数据分区。每个分区表都会维护修改它的所有操作的相关排序属性的各种元数据。元数据可让 BigQuery 在查询运行之前更准确地估算查询费用。


何时使用分区


在以下情况下,请考虑对表进行分区:

  • 你希望仅扫描表的一部分以改善查询性能。

  • 表操作超出了配额,你可以将表操作的范围限定为特定的分区列值。

  • 你希望在查询运行之前确定查询费用。在对分区表运行查询之前,BigQuery 会提供查询费用估算。通过删减分区表计算查询费用估算,然后发出查询试运行来估算查询费用。


在以下情况下,请考虑对表进行聚簇,而不是对表进行分区:

  • 你需要比分区允许更多的粒度。

  • 你的查询通常对多个列使用过滤器或聚合。

  • 一列或多列中值数量的基数较大。

  • 查询执行前无需严格的费用估算。


在这种情况下,表聚簇可让你根据用户定义的排序属性对特定列中的数据进行聚簇,从而加快查询速度。另外,还可以结合使用聚簇和表分区来实现更精细的排序。


分区类型


本部分将介绍对表进行分区的不同方法。


整数范围分区


您可以按照特定 INTEGER 列中的值范围对表进行分区。如需创建整数范围分区表,请提供以下各项:

  • 分区列。

  • 范围分区的起始值(含边界值)。

  • 范围分区的终止值(不含边界值)。

  • 分区中每个范围的间隔值。


例如,假设您使用以下规范创建了一个整数范围分区:




表将按 customer_id 列进行范围分区,间隔值为 10。值 0 到 9 进入一个分区,值 10 到 19 进入下一个分区,以此类推,最多 99 个。此范围以外的值会进入名为 __UNPARTITIONED__ 的分区中。customer_id 为 NULL 的所有行都会进入名为 __NULL__ 的分区。


时间单位列分区


您可以按照表的 DATE、TIMESTAMP 或 DATETIME 列对表进行分区。当您将数据写入表时,BigQuery 会根据列中的值自动将数据放入正确的分区。


对于 TIMESTAMP 和 DATETIME 列,分区可以具有每小时、每天、每月或每年的时间粒度。对于 DATE 列,分区可以具有每天、每月或每年的时间粒度。分区边界基于世界协调时间 (UTC)。


例如,假设您对包含 DATETIME 列的表按月分区。如果您将以下值插入表中,则行会写入以下分区:




此外,系统会创建两个特殊分区:

  • __NULL__:包含分区列中具有 NULL 值的行。

  • __UNPARTITIONED__:包含分区列的值早于 1960-01-01 或晚于 2159-12-31 的行。


提取时间分区


当您创建按提取时间分区的表时,BigQuery 会根据 BigQuery 提取数据时的时间自动将行分配到分区。您可以为分区选择每小时、每天、每月或每年的时间粒度。分区边界基于世界协调时间 (UTC)。


如果在使用更精细的时间粒度时,您的数据达到每个表 4000 个分区的限制,请改用更宽泛的粒度。例如,您可以通过每月(而不是每天)进行分区,以减少分区数量。您还可以对分区列进行聚簇,以进一步提升性能。


注入时间分区表具有名为 _PARTITIONTIME 的伪列。此列的值是每行的提取时间,截断至分区边界(例如每小时或每天)。例如,假设您创建了一个每小时分区的提取时间分区表,并在以下时间发送数据。




由于本例中的表使用每小时分区,因此 _PARTITIONTIME 的值被截断到小时边界。BigQuery 使用此值来确定数据的正确分区。


您还可以将数据写入特定分区。例如,您可能需要加载历史数据或根据时区进行调整。您可以使用 0001-01-01 和 9999-12-31 之间的任何有效日期。但是,DML 语句不能引用 1970-01-01 之前或 2159-12-31 之后的日期。如需了解详情,请参阅将数据写入特定分区。


除了使用 _PARTITIONTIME,您还可以使用 _PARTITIONDATE。_PARTITIONDATE 伪列包含与 _PARTITIONTIME 伪列中的值对应的世界协调时间 (UTC) 日期。


选择每日、每小时、每月或每年分区


按时间单位列或提取时间对表进行分区时,您可以选择分区是具有每日、每小时、每月还是每年的时间粒度。


  • 每日分区是默认分区类型。如果您的数据分布于多个日期范围内,或者如果数据随时间不断增加,则每日分区是一个不错的选择。

  • 如果您的表包含大量数据,且这些数据覆盖一个较短的日期范围(时间戳值通常小于六个月),请选择每小时分区。如果选择每小时分区,请确保分区数量不超出分区限制范围。

  • 如果您的表每天包含的数据量相对较少,但覆盖的日期范围很广,请选择每月或每年分区。如果您的工作流需要频繁更新或添加覆盖较广日期范围的行(例如超过 500 个日期),我们也建议您使用此选项。在这些场景中,请对分区列使用每月或每年分区以及聚簇操作,以获得最佳性能。


结合使用聚簇表和分区表


您可以结合使用表分区与表聚簇以实现精细的排序,从而进一步优化查询。


聚簇表包含根据用户定义的排序属性对数据进行排序的聚簇列。这些聚簇列中的数据会被分类为多个存储块,这些存储块根据表的大小进行自适应调整。当您运行按聚簇列过滤的查询时,BigQuery 仅根据聚簇列而不是相关表或表分区扫描相关块。在同时使用表分区和聚簇的方法中,首先将表数据分段为分区,然后按聚簇列对每个分区中的数据进行聚簇。


创建聚簇和分区的表时,您可以实现更精细的排序,如下图所示:




分区与分片的比较


表分片是使用 [PREFIX]_YYYYMMDD 等命名前缀将数据存储到多个表中的做法。


更推荐使用分区而不是表分片,因为分区表性能更佳。对于分片表,BigQuery 必须为每个表保留架构和元数据的副本。BigQuery 可能还需要分别为每个要查询的表验证权限。该做法也会增加查询开销,影响查询性能。


如果你之前创建了日期分片表,可以将其转换为提取时间分区表。


限制


无法使用旧版 SQL 查询分区表,也无法将查询结果写入分区表中。


BigQuery 不支持按多列进行分区;只能根据一列对表进行分区。


时间单位列分区表存在如下限制:

  • 分区列必须是标量 DATE、TIMESTAMP 或 DATETIME 列。虽然列模式可以是 REQUIRED 或 NULLABLE,但不能是 REPEATED(基于数组)。

  • 此外,分区列必须是顶级字段。不能将 RECORD (STRUCT) 中的叶字段用作分区列。


整数范围分区表存在如下限制:

  • 分区列必须为 INTEGER 列。虽然列模式可以是 REQUIRED 或 NULLABLE,但不能是 REPEATED(基于数组)。

  • 此外,分区列必须是顶级字段。不能将 RECORD (STRUCT) 中的叶字段用作分区列。


配额和限制


分区表在 BigQuery 中有确定的限制。


配额和限制也适用于针对分区表运行的不同类型的作业,其中包括:

  • 加载数据(加载作业)

  • 导出数据(导出作业)

  • 查询数据(查询作业)

  • 复制表(复制作业)


表价格


在 BigQuery 中创建和使用分区表时,您的费用取决于分区中存储的数据量以及对数据运行的查询:

  • 如需了解存储价格,请参阅存储价格。

(https://cloud.google.com/bigquery/pricing?hl=zh-cn#storage)

  • 如需了解查询价格,请参阅查询价格。

(https://cloud.google.com/bigquery/pricing?hl=zh-cn#analysis_pricing_models)


很多分区表操作都是免费的,包括将数据加载到分区、复制分区,以及从分区导出数据。这些操作虽然免费,但是受 BigQuery 的配额和限制约束。


返回全部