

# 使用动态 ID 分区


当数据按高基数属性分区时，或者无法事先知道这些值时，您可以使用 `injected` 投影类型。此类属性的示例包括用户名以及设备或产品的 ID。当您使用 `injected` 投影类型配置分区键时，Athena 使用查询本身的值来计算要读取的分区集。

如果某个表具有通过 `injected` 投影类型配置的分区键，则要使 Athena 能够在该表上运行查询，必须满足以下条件：
+ 查询必须包括至少一个分区键值。
+ 值必须是无需读取任何数据即可评估的文字或表达式。

只要其中一个条件不满足，查询就会失败，并显示以下错误：

CONSTRAINT\$1VIOLATION：对于注入的投影分区列 *column\$1name*，WHERE 子句必须仅包含静态相等条件，并且必须至少存在一个此类条件。

## 何时使用 `injected` 投影类型


设想您的数据集包含来自 IoT 设备的事件，并按设备的 ID 进行分区。该数据集具有以下特征：
+ 设备 ID 随机生成。
+ 新设备经常预置。
+ 目前有数十万台设备，将来会有数百万台。

使用传统的元数据存储很难管理此数据集。难以确保数据存储与元存储之间保持分区同步，而且在查询规划期间筛选分区可能很慢。但是，如果您将表配置为使用分区投影并使用 `injected` 投影类型，您会获得两个优势：您不必在元存储中管理分区，并且您的查询不必查找分区元数据。

以下 `CREATE TABLE` 示例会为刚刚描述的设备事件数据集创建一个表。该表使用注入投影类型。

```
CREATE EXTERNAL TABLE device_events (
  event_time TIMESTAMP,
  data STRING,
  battery_level INT
)
PARTITIONED BY (
  device_id STRING
)
LOCATION "s3://amzn-s3-demo-bucket/prefix/"
TBLPROPERTIES (
  "projection.enabled" = "true",
  "projection.device_id.type" = "injected",
  "storage.location.template" = "s3://amzn-s3-demo-bucket/prefix/${device_id}"
)
```

以下示例查询会查找在 12 小时内从三台特定设备收到的事件数。

```
SELECT device_id, COUNT(*) AS events
FROM device_events
WHERE device_id IN (
  '4a770164-0392-4a41-8565-40ed8cec737e',
  'f71d12cf-f01f-4877-875d-128c23cbde17',
  '763421d8-b005-47c3-ba32-cc747ab32f9a'
)
AND event_time BETWEEN TIMESTAMP '2023-11-01 20:00' AND TIMESTAMP '2023-11-02 08:00'
GROUP BY device_id
```

当您运行此查询时，Athena 会看到 `device_id` 分区键的三个值，并使用这些值来计算分区位置。Athena 使用 `storage.location.template` 属性的值来生成以下位置：
+ `s3://amzn-s3-demo-bucket/prefix/4a770164-0392-4a41-8565-40ed8cec737e`
+ `s3://amzn-s3-demo-bucket/prefix/f71d12cf-f01f-4877-875d-128c23cbde17`
+ `s3://amzn-s3-demo-bucket/prefix/763421d8-b005-47c3-ba32-cc747ab32f9a`

如果您在分区投影配置中省略了 `storage.location.template` 属性，Athena 会使用 Hive 风格分区，根据 `LOCATION` 中的值（例如，`s3://amzn-s3-demo-bucket/prefix/device_id=4a770164-0392-4a41-8565-40ed8cec737e`）投影分区位置。