在 Athena 中进行分区和分桶 - Amazon Athena
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

在 Athena 中进行分区和分桶

分区和分桶是减少运行查询时 Athena 必须扫描的数据量的两种方法。分区与分区互补,可以一起使用。可通过减少扫描的数据量提高性能并降低成本。有关 Athena 查询性能的一般准则,请参阅 Amazon Athena 的十大性能优化技巧

什么是分区?

分区指根据数据的特定属性将数据分到 Amazon S3 上的目录(或“前缀”)中。此类属性称为分区键。常见的分区键是日期或其他时间单位,例如年或月。但是,可按多个键一个数据集进行分区。例如,有关产品销售的数据可按日期、产品类别和市场进行分区。

确定分区方式

分区键的理想候选项为在查询中始终或经常使用且基数较低的属性。需要权衡分区数量,不能过多也不能过少。如果分区过多,文件数会增加,从而产生开销。筛选分区本身也会产生一些开销。如果分区过少,查询通常必须扫描更多数据。

创建分区表

对数据集进行分区后,可以在 Athena 中创建分区表。分区表是具有分区键的表。使用 CREATE TABLE 时,可以向表添加分区。使用 CREATE TABLE AS 时,在 Amazon S3 上创建的分区会自动添加至表。

CREATE TABLE 语句中,可在 PARTITIONED BY (column_name data_type) 子句中指定分区键。在 CREATE TABLE AS 语句中,可在 WITH (partitioned_by = ARRAY['partition_key']) 子句中或 Iceberg 表的 WITH (partitioning = ARRAY['partition_key']) 中指定分区键。出于性能考虑,分区键的类型应始终为 STRING。有关更多信息,请参阅使用字符串作为分区键的数据类型

有关其他 CREATE TABLECREATE TABLE AS 语法详细信息,请参阅 CREATE TABLECTAS 表属性

查询分区表

当您查询分区表时,Athena 使用查询中的谓词来筛选分区列表。然后,它使用匹配分区的位置来处理找到的文件。通过不读取与查询谓词不匹配的分区中的数据,Athena 可以有效地减少扫描的数据量。

示例

假设您拥有一个按 sales_dateproduct_category 分区的表,您希望了解一周内特定类别的总收入。您可以在 sales_dateproduct_category 列中包含谓词,以确保 Athena 仅扫描最低数量的数据,如以下示例所示。

SELECT SUM(amount) AS total_revenue FROM sales WHERE sales_date BETWEEN '2023-02-27' AND '2023-03-05' AND product_category = 'Toys'

假设您的数据集按日期进行分区,同时具有精细的时间戳。

对于 Iceberg 表,您可以将分区键声明为与列有关系,但是对于 Hive 表,查询引擎对列和分区键之间的关系一无所知。因此,您必须在列和查询的分区键中包含一个谓词,以确保查询仅扫描所需数量的数据。

例如,假设上一个示例中的 sales 表还包含一个数据类型为 TIMESTAMPsold_at 列。如果您只需要特定时间范围内的收入,查询编写如下:

SELECT SUM(amount) AS total_revenue FROM sales WHERE sales_date = '2023-02-28' AND sold_at BETWEEN TIMESTAMP '2023-02-28 10:00:00' AND TIMESTAMP '2023-02-28 12:00:00' AND product_category = 'Toys'

有关查询 Hive 和 Iceberg 表之间的差异的更多信息,请参阅 如何为同时按时间分区的时间戳字段编写查询

什么是分桶?

分桶是一种将数据集记录分为称为存储桶的类别的方法。

这里的存储桶分桶的含义与 Amazon S3 存储桶不同,不应与之混淆。在数据分桶中,具有相同属性值的记录会进入同一存储桶中。记录在存储桶之间尽可能均匀地分布,因此每个存储桶的数据量大致相同。

实际上,存储桶就是文件,哈希函数决定了记录进入哪个存储桶。分桶数据集的每个分区的每个存储桶将包含一个或多个文件。文件所属的存储桶以文件名编码。

分桶优势

如果数据集按特定属性进行分桶,并且您想要检索该属性具有特定值的记录,建议使用分桶。由于数据已分桶,Athena 可以使用该值来确定要查看的文件。例如,假设一个数据集按 customer_id 进行分桶,并且您想要查找特定客户的所有记录。Athena 确定包含这些记录的存储桶,并且仅读取该存储桶中的文件。

如果您的列具有高基数(即具有许多不同值)、分布均匀且您经常查询特定值,这些都适合作为分桶的依据。

注意

Athena 不支持使用 INSERT INTO 向分桶表添加新记录。

对分桶列进行筛选所支持的数据类型

您可以在具有特定数据类型的分桶列中添加筛选器。Athena 在具有以下数据类型的分桶列上支持筛选:

  • BOOLEAN

  • BYTE

  • DATE

  • DOUBLE

  • FLOAT

  • INT

  • LONG

  • SHORT

  • string

  • VARCHAR

Hive 和 Spark 支持

Athena 引擎版本 2 支持使用 Hive 存储桶算法对数据集进行分区,而 Athena 引擎版本 3 也支持 Apache Spark 分桶算法。Hive 分桶为默认设置。如果您的数据集使用 Spark 算法进行分桶,使用 TBLPROPERTIES 子句将 bucketing_format 属性值设置为 spark

注意

在一个 CREATE TABLE AS SELECTCTAS)查询中,Athena 的分区数量不能超过 100 个。同样,您可以使用 INSERT INTO 语句向目标表最多添加 100 个分区。100 个分区的限制仅在对表进行分桶和分区时适用。

如果超过此限制,则可能会收到错误消息 HIVE_TOO_MANY_OPEN_PARTITIONS: Exceeded limit of 100 open writers for partitions/buckets(HIVE_TOO_MANY_OPEN_PARTITIONS:分区/存储桶超过 100 个打开的写入程序限制)。要绕过此限制,您可以使用一个 CTAS 语句和一系列 INSERT INTO 语句,每个后一种语句将创建或插入不超过 100 个分区。有关更多信息,请参阅使用 CTAS 和 INSERT INTO 绕过 100 分区限制

分桶 CREATE TABLE 示例

要为现有分桶数据集创建表,使用 CLUSTERED BY (column) 子句后跟 INTO N BUCKETS 子句。INTO N BUCKETS 子句指定用于对数据进行分桶的存储桶数。

在以下 CREATE TABLE 示例中,使用 Spark 算法按 customer_idsales 数据集分为 8 个存储桶。CREATE TABLE 语句使用 CLUSTERED BYTBLPROPERTIES 子句相应地设置属性。

CREATE EXTERNAL TABLE sales (...) ... CLUSTERED BY (`customer_id`) INTO 8 BUCKETS ... TBLPROPERTIES ( 'bucketing_format' = 'spark' )

分桶 CREATE TABLE AS(CTAS)示例

要使用 CREATE TABLE AS 指定分桶,使用 bucketed_bybucket_count 参数,如以下示例所示。

CREATE TABLE sales WITH ( ... bucketed_by = ARRAY['customer_id'], bucket_count = 8 ) AS SELECT ...

分桶查询示例

以下示例查询将查找特定客户在一周内购买的产品的名称。

SELECT DISTINCT product_name FROM sales WHERE sales_date BETWEEN '2023-02-27' AND '2023-03-05' AND customer_id = 'c123'

如果此表按 sales_date 进行分区并按 customer_id 进行分桶,则 Athena 可以计算出客户记录所在的存储桶。Athena 最多读取每个分区中的一个文件。

另请参阅

有关创建分桶表和分区表的 CREATE TABLE AS 示例,请参阅示例:创建分桶表和分区表