

# 什么是分桶？
<a name="ctas-partitioning-and-bucketing-what-is-bucketing"></a>

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

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

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

## 分桶优势
<a name="ctas-partitioning-and-bucketing-bucketing-benefits"></a>

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

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

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

## 对分桶列进行筛选所支持的数据类型
<a name="ctas-partitioning-and-bucketing-data-types-supported-for-filtering-on-bucketed-columns"></a>

您可以在具有特定数据类型的分桶列中添加筛选器。Athena 在具有以下数据类型的分桶列上支持筛选：
+ BOOLEAN
+ BYTE
+ DATE
+ DOUBLE
+ FLOAT
+ INT
+ LONG
+ SHORT
+ string
+ VARCHAR

## Hive 和 Spark 支持
<a name="ctas-partitioning-and-bucketing-hive-and-spark-support"></a>

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

**注意**  
在一个 `CREATE TABLE AS SELECT`（[CTAS](ctas.md)）查询中，Athena 的分区数量不能超过 100 个。同样，您可以使用 [INSERT INTO](insert-into.md) 语句向目标表最多添加 100 个分区。  
如果超过此限制，则可能会收到错误消息 HIVE\$1TOO\$1MANY\$1OPEN\$1PARTITIONS: Exceeded limit of 100 open writers for partitions/buckets（HIVE\$1TOO\$1MANY\$1OPEN\$1PARTITIONS：分区/存储桶超过 100 个打开的写入程序限制）。要绕过此限制，您可以使用一个 CTAS 语句和一系列 `INSERT INTO` 语句，每个后一种语句将创建或插入不超过 100 个分区。有关更多信息，请参阅 [使用 CTAS 和 INSERT INTO 绕过 100 分区限制](ctas-insert-into.md)。

## 分桶 CREATE TABLE 示例
<a name="ctas-partitioning-and-bucketing-bucketing-create-table-example"></a>

要为现有分桶数据集创建表，使用 `CLUSTERED BY (column)` 子句后跟 `INTO N BUCKETS` 子句。`INTO 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）示例
<a name="ctas-partitioning-and-bucketing-bucketing-create-table-as-example"></a>

要使用 `CREATE TABLE AS` 指定分桶，使用 `bucketed_by` 和 `bucket_count` 参数，如以下示例所示。

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

## 分桶查询示例
<a name="ctas-partitioning-and-bucketing-bucketing-query-example"></a>

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

```
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 最多读取每个分区中的一个文件。