在 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['
子句中或 Iceberg 表的 partition_key
'])WITH (partitioning =
ARRAY['
中指定分区键。出于性能考虑,分区键的类型应始终为 partition_key
'])STRING
。有关更多信息,请参阅使用字符串作为分区键的数据类型。
有关其他 CREATE TABLE
和 CREATE TABLE AS
语法详细信息,请参阅 CREATE TABLE 和 CTAS 表属性。
查询分区表
当您查询分区表时,Athena 使用查询中的谓词来筛选分区列表。然后,它使用匹配分区的位置来处理找到的文件。通过不读取与查询谓词不匹配的分区中的数据,Athena 可以有效地减少扫描的数据量。
示例
假设您拥有一个按 sales_date
和 product_category
分区的表,您希望了解一周内特定类别的总收入。您可以在 sales_date
和 product_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
表还包含一个数据类型为 TIMESTAMP
的 sold_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
。
注意
Athena 引擎版本 2 在 CREATE TABLE AS SELECT
(CTAS)查询中的分区数不超过 100 个。同样,您可以使用 INSERT INTO 语句向目标表最多添加 100 个分区。仅当对表进行分桶和分区时,Athena 引擎版本 2 中的此 100 限制才适用。
如果超过此限制,则可能会收到错误消息 HIVE_TOO_MANY_OPEN_PARTITIONS: Exceeded limit of 100 open writers for partitions/buckets
(HIVE_TOO_MANY_OPEN_PARTITIONS:分区/存储桶超过 100 个打开的写入程序限制)。要绕过 Athena 引擎版本 2 中的此限制,您可以使用一个 CTAS 语句和一系列 INSERT INTO
语句,每个语句将创建或插入不超过 100 个分区。有关更多信息,请参阅使用 CTAS 和 INSERT INTO 绕过 100 分区限制。
分桶 CREATE TABLE 示例
要为现有分桶数据集创建表,使用 CLUSTERED BY
(
子句后跟 column
)
INTO
子句。N
BUCKETSINTO
子句指定用于对数据进行分桶的存储桶数。N
BUCKETS
在以下 CREATE TABLE
示例中,使用 Spark 算法按 customer_id
将 sales
数据集分为 8 个存储桶。CREATE TABLE
语句使用 CLUSTERED BY
和 TBLPROPERTIES
子句相应地设置属性。
CREATE EXTERNAL TABLE sales (...) ... CLUSTERED BY (`customer_id`) INTO 8 BUCKETS ... TBLPROPERTIES ( 'bucketing_format' = 'spark' )
分桶 CREATE TABLE AS(CTAS)示例
要使用 CREATE TABLE AS
指定分桶,使用 bucketed_by
和 bucket_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
示例,请参阅示例:创建分桶表和分区表。