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

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

中的性能优化Athena

本主题提供了一般信息以及特定建议,当您有大量数据并遇到内存使用或性能问题时,是为了提高 Athena 的性能。

物理限制

通常,Athena 将每个查询的运行时限制为 30 分钟。将自动取消超出此限制的查询。如果查询用尽内存或在处理期间节点崩溃,则可能发生类似下面的错误:

INTERNAL_ERROR_QUERY_ENGINE
EXCEEDED_MEMORY_LIMIT: Query exceeded local memory limit
Query exhausted resources at this scale factor
Encountered too many errors talking to a worker node. The node may have crashed or be under too much load.

查询优化技术

对于需要超出现有限制的资源的查询,您可以优化查询或调整查询的数据结构。要优化您的查询,请考虑此部分中的建议。

数据大小

避免单个大文件 单个文件加载到单个节点中进行处理。–如果您的文件大小非常大,请尝试将文件拆分为较小的文件,并使用分区来组织它们。

同时读取少量数据 一次扫描大量数据可能会降低查询速度并增加成本。–使用分区或筛选条件限制要扫描的文件。

避免包含过多列 – 消息 GENERIC_INTERNAL_ERROR: io.airlift.bytecode.CompilationException 在 Athena 无法将查询编译到字节码时, 可能会发生。此异常通常是由查询中的列过多导致的。减少查询中的列数或创建子查询,并使用可检索少量数据的 JOIN

避免大型查询输出 – 因为查询结果是由单个 Amazon S3 节点写入到 Athena 的,所以大量输出数据会降低性能。要解决此问题,请尝试使用 CTAS 创建包含查询结果的新表,或使用 INSERT INTO 将新结果附加到现有表中。

避免带有大型输出的 CTAS 查询 – 因为输出数据由单个节点写入,所以 CTAS 查询也可以使用大量内存。如果您要输出大量数据,请尝试将任务分成多个较小的查询。

如果可能,请避免使用大量小文件 – Amazon S3 具有每秒 5500 个请求的限制。Athena 查询具有相同的限制。如果您需要在单个查询中扫描数百万个小型对象,Amazon S3 可以轻松地限制您的查询。为避免扫描过多,请使用 AWS Glue ETL 定期压缩您的文件或对表进行分区并添加分区键筛选条件。有关更多信息,请参阅 开发人员指南中的以较大组读取输入文件AWS Glue或 知识中心中的 AWS Glue AWS Glue ETL 作业以输出较大的文件?AWS。

避免扫描整个表 使用以下方法可避免扫描整个表:–

  • 限制使用“*”。除非有必要,否则尽量不要选择所有列。

  • 避免在同一查询中多次扫描同一表

  • 使用筛选条件来减少要扫描的数据量。

  • 如果可能,请添加 LIMIT 子句。

避免在单个查询中引用许多视图和表 – 因为具有许多视图和/或表的查询必须将大量数据加载到单个节点,所以可能会发生内存不足错误。如果可能,请尽量避免在单个查询中引用过多的视图或表。

避免大型 JSON 字符串 如果数据存储在单个 JSON 字符串中且 JSON 数据大小很大,处理 JSON 数据时可能会发生内存不足错误。–

文件格式

使用有效的文件格式(如 Parquet 或 ORC)– 要显著减少查询运行时间和成本,请使用压缩的 Parquet 或 ORC 文件来存储您的数据。要将现有数据集转换为 Athena 中的这些格式,您可以使用 CTAS。有关更多信息,请参阅 将 CTAS 和 INSERT INTO 用于 ETL 和数据分析.

在 ORC 和 Parquet 格式之间切换 – 经验显示,同一组数据在处理时间上可能存在明显差异,具体取决于它是以 ORC 格式还是以 Parquet 格式存储。如果您遇到性能问题,请尝试其他格式。

Hudi 查询 – 因为 Hudi 查询会绕过 parquet 格式的文件的本机读取器和拆分生成器,所以它们速度较慢。在查询 Hudi 数据集时,请记住这一点。

联接、分组和并集

减少内存密集型操作的使用 – 操作(如 JOINGROUP BYORDER BYUNION)都需要将大量数据加载到内存中。要加快您的查询速度,请找出其他方法来实现相同的结果,或尽可能将 LIMIT 等子句添加到外部查询。

考虑使用 UNION ALL – 为了消除重复项,UNION 将构建占用内存的哈希表。如果您的查询不需要删除重复项,请考虑使用 UNION ALL 以获得更好的性能。

使用 CTAS 作为中间步骤来加快 JOIN 操作 – 使用 CTAS 将中间数据保存到 Amazon S3 中,而不是在每次查询中加载和处理中间数据。这有助于提高 JOIN 等操作的性能。

Partitioning

限制表中的分区数 – 当表具有超过 100,000 个分区时,查询的速度可能会比较慢,因为发送到 AWS Glue 以检索分区信息的请求数很大。要解决此问题,请尝试以下选项之一:

删除旧分区(即使它们为空) – 即使分区为空,分区的元数据仍存储在 AWS Glue 中。加载这些不需要的分区可能会增加查询运行时。要删除不需要的分区,请使用 ALTER TABLE DROP PARTITION

查找单个分区 – 在查找单个分区时,请尝试提供所有分区值,以便 Athena 可以使用对 AWS Glue 的单一调用来查找分区。否则,Athena 必须检索所有分区并筛选它们。这可能会成本高昂,并显著增加查询的规划时间。如果您有可预测的分区模式,则可以使用分区投影 来避免对 AWS Glue 进行分区查找调用。

设置合理的分区投影属性 – 使用分区投影时,Athena 尝试为每个分区名称创建一个分区对象。因此,请确保您定义的表属性不会创建几乎无限数量的可能分区。

要频繁添加新分区,请使用 ALTER TABLE ADD PARTITION – 如果您使用 MSCK REPAIR TABLE 频繁添加新分区(例如,每天)并且正在遇到查询超时,请考虑使用 ALTER TABLE ADD PARTITIONMSCK REPAIR TABLE 是在首次创建表时或数据与分区元数据之间存在奇偶校验不确定性时使用的。

避免在具有分区列的 WHERE 子句中使用 coalesce() 在某些情况下,在 – 子句中针对分区列使用 coalesce() 或其他函数可能会导致性能下降。WHERE如果发生这种情况,请尝试重新编写查询以提供相同的功能,而无需使用 coalesce()

开窗函数

尽可能减少窗口函数的使用窗口函数(如 rank())是内存密集型的。一般来说,窗口函数需要将整个数据集加载到单个 Athena 节点中以进行处理。对于非常大的数据集,这可能会有造成节点崩溃的风险。要避免这种情况,请尝试以下选项:

  • 筛选数据并对一部分数据运行窗口函数。

  • 尽可能将 PARTITION BY 子句与窗口函数一起使用。

  • 查找构建查询的替代方法。

使用更有效的 函数

替换 row_number() OVER (...) as rnk ... WHERE rnk = 1 – 要用与此类似的 row_number() 子句加快查询速度,请将此语法替换为 GROUP BYORDER BYLIMIT 1 的组合。

在大型字符串上使用正则表达式而不是 LIKE 在大型字符串上使用包含 – 等子句的查询的成本很高。LIKE '%string%'考虑改用 regexp_like() 函数和正则表达式。

使用 max() 而不是 element_at(array_sort(), 1) 要提高速度,请将嵌套函数 – 替换为 element_at(array_sort(), 1)max()

其他资源

有关 Athena 中的性能优化的其他信息,请考虑以下资源: