AWS Athena 分区获取所有路径

Posted

技术标签:

【中文标题】AWS Athena 分区获取所有路径【英文标题】:AWS Athena partition fetch all paths 【发布时间】:2020-04-16 16:39:01 【问题描述】:

最近,当分区数量非常多时,我在使用 AWS Athena 时遇到了问题。

旧版本的数据库和表只有 1 个分区级别,比如 id=x。我们来一张桌子;例如,我们存储每个 id(产品)的支付参数,并且没有足够的 ID。假设它在1000-5000左右。现在,在查询该表时,在 where 子句(如“.. where id = 10”)上传递 id 号。实际上,查询的返回速度非常快。假设我们每天更新两次数据。

最近,我们一直在考虑为一天添加另一个分区级别,例如“../id=x/dt=yyyy-mm-dd/..”。这意味着如果一个月过去了,分区数每天会增加 xID 次,如果我们有 3000 个 ID,我们每月大约会获得 3000x30=90000 个分区。因此,分区数量迅速增长。

假设 3 个月大的数据(约 27 万个分区),我们希望看到类似以下的查询最多会在 20 秒左右返回。

select count(*) from db.table where id = x and dt = 'yyyy-mm-dd'

这需要一分钟。

真实案例

事实证明,Athena 首先获取所有分区(元数据)和 s3 路径(不管 where 子句的用法),然后过滤您希望在 where 条件下查看的那些 s3 路径。第一部分(按分区获取所有 s3 路径的持续时间与分区数量成正比)

您拥有的分区越多,执行的查询就越慢。

直观地说,我预计 Athena 只获取 where 子句中声明的 s3 路径,我的意思是这将是分区的一种神奇方式。也许它会获取所有路径

是否有人知道解决方法,或者我们是否以错误的方式使用 Athena? 是否应仅将 Athena 用于少量分区?

编辑

为了澄清上面的陈述,我从支持邮件中添加了一条。

来自支持

... 您提到您的新系统有 360000,这是一个巨大的数字。 所以当你在做select * from <partitioned table>时,Athena 首先下载所有分区元数据并搜索映射的 S3 路径 那些分区。这个为每个分区获取数据的过程 导致查询执行时间更长。 ...

更新

在 AWS 论坛上打开了一个问题。在 aws 论坛上提出的链接问题是 here。

谢谢。

【问题讨论】:

您是否已经考虑过分桶? @PiotrFindeisen 你的意思是分桶天而不是分区天?我没有尝试过,但它会加速where子句吗?如果您打算获得最佳文件数,您可以假设我们在每个分区中都有最佳文件数 我不知道你的查询模式(这是关键部分,真的)。直觉上,我会先尝试按dt 进行分区,然后按id 进行分桶。但是,我不知道您为什么按id 进行分区以及id 实际上是什么。此外,没有最佳文件数之类的东西。如果您使用 ORC 或 Parquet,您只需关心文件至少为 32-64MB,但单个文件可能会很大。 顺便说一句,正如您所见,这不是一个非常适合的简单问题,并且没有单一的答案。我建议您通过Presto community slack 咨询 Presto 专家。 @null :这可能对您的用例很有帮助:aws.amazon.com/premiumsupport/knowledge-center/… 【参考方案1】:

如果不知道数据量、文件格式以及我们正在讨论的文件数量,这是不可能正确回答的。

TL; DR 我怀疑您有包含数千个文件的分区,并且瓶颈是列出并全部读取它们。

对于任何随时间增长的数据集,您都应该根据查询模式在日期甚至时间上进行时间分区。如果您应该对其他属性进行分区取决于很多因素,最终结果往往是不分区更好。不总是,但经常。

在许多情况下,使用合理大小(~100 MB)的 Parquet 比分区更有效。原因是分区增加了必须在 S3 上列出的前缀数量以及必须读取的文件数量。在许多情况下,一个 100 MB Parquet 文件比十个 10 MB 文件更有效。

当 Athena 执行查询时,它将首先从 Glue 加载分区。 Glue supports limited filtering on partitions,并且将有助于修剪分区列表 - 所以据我所知,Athena 读取 所有 分区元数据是不正确的。

当它拥有分区时,它将向分区位置发出LIST 操作以收集查询中涉及的文件——换句话说,Athena 不会列出每个分区位置,只是为查询选择的分区中的那些。这可能仍然是一个很大的数字,这些列表操作肯定是一个瓶颈。如果一个分区中有超过 1000 个文件会变得特别糟糕,因为这是 S3 列表操作的页面大小,并且必须按顺序发出多个请求。

列出所有文件后,Athena 将生成一个拆分列表,该列表可能等于也可能不等于文件列表 - 某些文件格式是可拆分的,如果文件足够大,它们将被拆分并并行处理。

只有在完成所有这些工作之后,实际的查询处理才会开始。根据拆分的总数和 Athena 集群中的可用容量,您的查询将被分配资源并开始执行。

如果您的数据是 Parquet 格式,并且每个分区有一个或几个文件,那么您问题中的计数查询应该在一秒钟或更短的时间内运行。 Parquet 文件中有足够的元数据,计数查询不必读取数据,只需读取文件页脚即可。由于涉及多个步骤,很难让任何查询在不到一秒的时间内运行,但是命中单个分区的查询应该可以快速运行。

由于需要两分钟,我怀疑每个分区有数百个文件,如果不是数千个,你的瓶颈是运行所有列表并在 S3 中获取操作需要太多时间。

【讨论】:

感谢您的详细回答。实际上,正如您所说,我们已经寻求最佳文件大小(存储镶木地板),但瓶颈是 s3 列表,这可能是由于 s3 列表的分页为 1000 页。我们的问题是在粘合上应用两个分区列,这不是最佳实践,因此我们将表结构更改为每个表应用 1 个分区列,它几乎解决了这个问题。

以上是关于AWS Athena 分区获取所有路径的主要内容,如果未能解决你的问题,请参考以下文章

使用 AWS Glue Scala 查询 Athena(添加分区)

在 athena aws 中具有不同分区的表

AWS Athena 创建表和分区

AWS Athena - GENERIC_INTERNAL_ERROR:分区值的数量与过滤器的数量不匹配

AWS Athena 无法将 .csv 整数转换为表值

AWS Athena JDBC 驱动程序并在 Maven 存储库中找到?