

# 数据分区


## 什么是数据分区？


 数据分区是指将大型数据集分为更小、更易于管理的区段的技术，这些区段称为分区。在 Amazon Glue 零 ETL 集成的背景下，分区将根据特定的列值或这些值的转换，在目标位置组织数据。

### 数据分区的好处


 有效的数据分区为分析工作负载带来了以下几大好处：
+  **提高查询性能：**查询可跳过不相关的分区（分区修剪），从而减少需要扫描的数据量。
+  **降低成本：**扫描数据变少，就可以减小分析查询的计算和 I/O 成本。
+  **增强可扩展性：**分区可以并行处理数据段，从而更有效地扩展分析工作负载。
+  **简化数据生命周期管理：**可以在分区级别管理保留策略，从而更轻松地存档或删除较旧的数据。

### 重要的分区概念


分区列  
 数据中用于确定如何将记录组织成分区的列。有效的分区列应与常见的查询模式一致，并具有适当的基数。

分区函数  
 应用于分区列值以创建实际分区边界的转换。例如包括身份（使用原始值）和基于时间的函数（年、月、日、小时）。

分区修剪  
 查询引擎识别并跳过不含查询相关数据的分区的过程，可显著提高性能。

分区粒度  
 对数据进行分区的详细程度。细粒度（较多的分区）可提高查询性能，但可能会增加元数据开销。粗粒度（较少的分区）可减小元数据开销，但可能会导致不必要地扫描更多数据。

### Amazon Glue 零 ETL 集成中的分区


 Amazon Glue 零 ETL 集成使用具有高级分区功能的 Apache Iceberg 表格式。创建零 ETL 集成时，您可以：
+ 使用针对数据源进行优化的默认分区策略
+ 定义按查询模式量身定制的自定义分区规范
+ 对分区列应用转换（尤其适用于基于时间戳的分区）
+ 结合使用多种分区策略进行多级分区

 在设置零 ETL 集成时，通过 `CreateIntegrationTableProperty` API 指定分区配置。一旦配置完成之后，Amazon Glue 会自动应用这些分区策略，在目标位置组织数据。

## 分区规范 API 参考


使用 CreateIntegrationTableProperties API 中的以下参数来配置分区：

PartitionSpec  
分区规范数组，定义如何在目标位置对数据进行分区。  

```
{
  "partitionSpec": [
    {
      "fieldName": "timestamp_col",
      "functionSpec": "month",
      "conversionSpec": "epoch_milli"
    },
    {
      "fieldName": "category",
      "functionSpec": "identity"
    }
  ]
}
```

FieldName  
指定用于分区的列名的 UTF-8 字符串（1-128 字节）。

FunctionSpec  
指定分区函数。有效值：  
+ `identity` - 无需转换即可直接使用源值
+ `year` - 从时间戳值中提取年份（例如，2023 年）
+ `month` - 从时间戳值中提取月份（例如，2023 年 1 月）
+ `day` - 从时间戳值中提取日期（例如，2023 年 1 月 15 日）
+ `hour` - 从时间戳值中提取小时数（例如，2023 年 1 月 15 日 14 时）
 基于时间的函数（`year`、`month`、`day`、`hour`）需要 `ConversionSpec` 参数来指定源时间戳格式。

ConversionSpec  
 指定源数据的时间戳格式的 UTF-8 字符串。有效值为：  
+ `epoch_sec` - Unix epoch 时间戳（以秒为单位）
+ `epoch_milli` - Unix epoch 时间戳（以毫秒为单位）
+ `iso` - ISO 8601 格式的时间戳

## 分区策略


### 默认分区


 如果未指定分区列，Amazon Glue 零 ETL 会应用针对数据源进行优化的默认分区策略：
+  **基于主键的分区：**对于具有主键的源（比如 DynamoDB 表），Amazon Glue 零 ETL 会自动使用主键对数据进行分区，并进行分桶以防止分区爆炸。

 默认分区的设计可以很好地处理常见的查询模式，无需手动配置。但是，对于特定的查询模式或性能要求，可能需要定义自定义的分区策略。

### 用户自定义的分区策略


 Amazon Glue 零 ETL 允许使用 `PartitionSpec` 参数定义自定义的分区策略。可指定一个或多个分区列，并对每列应用不同的分区函数。

 **身份分区**使用列中的原始值来创建分区。该策略适用于中低基数列（例如类别、区域或状态字段）。

**Example 身份分区示例**  

```
{
  "partitionSpec": [
    {
      "fieldName": "category",
      "functionSpec": "identity"
    }
  ]
}
```
 该示例将为“类别”列中的各个唯一值创建单独的分区。

**警告**  
 避免对高基数列（例如主键或时间戳）使用身份分区，因为这会导致分区爆炸，从而使性能下降并增加元数据开销。

 **基于时间的分区**根据时间戳值以不同的粒度（年、月、日或小时）组织数据。该策略是时间序列数据理想之选，可以实现高效的时间范围查询。

 使用基于时间的分区时，Amazon Glue 零 ETL 可以在应用该分区函数之前，自动将各种时间戳格式转换为标准化格式。这种转换是使用 `ConversionSpec` 参数指定的。

**Example 基于时间的分区示例**  

```
{
  "partitionSpec": [
    {
      "fieldName": "created_at",
      "functionSpec": "month",
      "conversionSpec": "epoch_milli"
    }
  ]
}
```
 该示例将根据“created\$1at”列按月对数据进行分区，该列中含有以毫秒为单位的 Unix epoch 时间戳。

 Amazon Glue 零 ETL 支持以下基于时间的分区函数：
+  **年：**按年对数据进行分区（例如，2023、2024 年） 
+  **月：**按月对数据进行分区（例如，2023 年 1 月、2023 年 2 月） 
+  **天：**按天对数据进行分区（例如，2023 年 1 月 1 日、2023 年 1 月 2 日） 
+  **小时：**按小时对数据进行分区（例如，2023 年 1 月 1 日 1 时、2023 年 1 月 1 日 2 时） 

 Amazon Glue 零 ETL 通过 `ConversionSpec` 参数支持以下时间戳格式：
+  **epoch\$1sec：**以秒为单位的 Unix epoch 时间戳 
+  **epoch\$1milli：**以毫秒为单位的 Unix epoch 时间戳 
+  **iso：**ISO 8601 格式的时间戳 

**注意**  
 源数据中的原始列值保持不变。AmazonGlue 仅会将分区列值转换为目标数据库表中的时间戳类型。该转换仅适用于分区过程。

 **多级分区**结合使用多种分区策略来创建分层分区方案。适用于针对同一数据集优化不同类型的查询。

**Example 多层分区示例**  

```
{
  "partitionSpec": [
    {
      "fieldName": "created_at",
      "functionSpec": "month",
      "conversionSpec": "iso"
    },
    {
      "fieldName": "region",
      "functionSpec": "identity"
    }
  ]
}
```
 该示例将创建一个两级分区方案：首先按月（来自“created\$1at”列）分区，然后按区域分区。这样就可以实现按日期范围、特定区域或这些维度的组合进行筛选的高效查询。

 在设计多级分区方案时，需要考虑：
+  将高选择性列置于分区层次结构的首位 
+  在分区粒度与分区数量之间实现平衡 
+  使分区方案与最常见的查询模式保持一致 

## 最佳实践


### 分区列选择

+  不要将高基数列与 `identity` 分区函数一起使用。使用具有标识分区的高基数列会创建许多小分区，这会显著降低摄取性能。高基数列可能包括：
  + 主键
  + 时间戳字段（例如 `LastModifiedTimestamp`、`CreatedDate`）
  + 系统生成的时间戳
+  请勿在同一列上选择多个时间戳分区。例如：

  ```
  "partitionSpec": [
        {"fieldName": "col1", "functionSpec": "year", "conversionSpec" : "epoch_milli"},
        {"fieldName": "col1", "functionSpec": "month", "conversionSpec" : "epoch_milli"},
        {"fieldName": "col1", "functionSpec": "day", "conversionSpec" : "epoch_milli"},
        {"fieldName": "col1", "functionSpec": "hour", "conversionSpec" : "epoch_milli"}
  ]
  ```

### 分区 FunctionSpec/ConversionSpec 选择

+  指定正确的 ConversionSpec (epoch\$1sec \$1 epoch\$1milli \$1 iso)，它表示在使用基于时间戳的分区函数时为基于时间戳的分区选择的列值的格式。AmazonGlue 零 ETL 使用此参数在分区之前将源数据正确转换为时间戳格式。
+  根据数据量使用适当的粒度（年/月/日/小时）。
+  使用 ISO 时间戳时请考虑时区影响。AmazonGlue 零 ETL 使用 UTC 时区填充所选时间戳列的所有记录值。

## 错误处理


### NEEDS\$1ATTENTION 状态


 当出现以下情况时，集成将进入 NEEDS\$1ATTENTION 状态：
+ 源中不存在指定的分区列
+ 分区列的时间戳转换失败