动态 ID 分区 - Amazon Athena
AWS 文档中描述的 AWS 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅中国的 AWS 服务入门

如果我们为英文版本指南提供翻译,那么如果存在任何冲突,将以英文版本指南为准。在提供翻译时使用机器翻译。

动态 ID 分区

您可能已基于具有以下特征的唯一标识符列对表进行分区:

  • 经常添加新值(也许是自动添加的)。

  • 无法轻松生成。它们可能是用户名或具有不同组合或长度的设备 ID,而不是定义的范围内的连续整数。

对于此类分区方案,将无法使用,enum 投影类型,原因如下:

  • 每次向表中添加值时,您都必须修改表属性。

  • 单个表属性将包含数百万个或更多字符。

  • 投影操作要求为投影配置所有分区列。仅对于一个列而言,就无法避免此要求。

要克服这些限制,可以使用 injectionbucketing

Injection

如果动态 ID 数据集上的查询模式始终为高基数分区列指定单个值,则可使用值注入。利用注入,便无需对整个分区空间进行投影。

想象您希望在具有极高的Cardinality类似的UUID字段分区物联网数据集 device_id...该字段具有以下特性:

  • 极度多(可能是数十亿)的值。

  • 由于其值是随机字符串,因此无法使用其他投影方法进行投影。

  • 无法在常用元存储中存储极大数量的分区。

不过,如果所有查询都包含一个 WHERE 子句,该子句仅筛选出一个 device_id,则可在 CREATE TABLE 语句中使用以下方法。

... PARTITIONED BY ( device_id STRING ) LOCATION "s3://bucket/prefix/" TBLPROPERTIES ( "projection.enabled" = "true", "projection.device_id.type" = "injected", "storage.location.template" = "s3://bucket/prefix/${device_id}" )

此类表上的 SELECT 查询如下所示:

SELECT col1, col2,..., device_id FROM table WHERE device_id = "b6319dc2-48c1-4cd5-a0a3-a1969f7b48f7" AND ( col1 > 0 or col2 < 10 )

在此示例中,Athena 仅对任何给定查询的一个分区进行投影。这样一来,便无需存储或操作数百万或数十亿个虚拟分区,而只需查找一个分区并从中进行读取。

Bucketing

在分桶技术中,您可以使用一组固定的存储桶值而非整组标识符来进行分区。如果您能够将标识符映射到存储桶,则可在查询中使用此映射。在对标识符本身进行分区时,您仍将受益。

与注入相比,分桶具有以下优势:

  • 您可以一次为 WHERE 子句中的一个字段指定多个值。

  • 您可以继续将您的分区与更传统的元存储结合使用。

还是在上一个示例中的场景中,假设 100 万个存储桶(由整数标识),该 CREATE TABLE 语句将变为以下内容。

... PARTITIONED BY ( BUCKET_ID BIGINT ) LOCATION "s3://bucket/prefix/" TBLPROPERTIES ( "projection.enabled" = "true", "projection.bucket_id.type" = "integer", "projection.bucket_id.range" = "1,1000000" )

相应的 SELECT 查询在 WHERE 子句中使用映射函数,如以下示例所示。

SELECT col1, col2,..., identifier FROM table WHERE bucket_id = map_identifier_to_bucket("ID-IN-QUESTION") AND identifier = "ID-IN-QUESTION"

更换 map_identifier_to_bucket 示例中的函数具有将标识符映射到整数的任何标度表达式。例如,表达式可以是简单的散列或模数。该函数对可以投影到指定维度上的分区的数量强制施加一个恒定上限。与支持谓词下推的文件格式(例如,Apache Parquet 或 ORC)配对时,存储桶技术可以提供良好的性能。

有关编写自己的用户定义的函数(如前面示例中的标量分桶函数)的信息,请参阅使用用户定义的函数进行查询(预览)