在读取时将分区分配给执行器

问题描述 投票:0回答:1

火花> 3.0

DBR 13.2

我有一些大型增量表,所有这些表都连接在同一个唯一的整数 id 上。

贷款

统一_ID 贷款编号 到期_日期
1 ABC 2023-01-01
2 CDE 2023-01-02
3 EFG 2023-01-03
8亿 ZZZ 2023-01-04

收藏

统一_ID 收集_尝试 收藏_日期
1 ABC 2023-01-01
8亿 ZZZ 2023-01-04

运行时间较长时遇到问题,似乎因一些严重的洗牌和排序步骤而成为瓶颈。出于此问题的目的,请忽略模型设计方面。

可以通过仔细选择分区和初始写入顺序来避免洗牌和排序步骤吗?例如,假设我按顺序 id 中的每 100 万个块进行分区。

所以,对于所有我喜欢的桌子:

分区编号 id_下限 id_下限
1 1 999999
2 1000000 1999999
7000 7000000000 7000999999

如果我最初按 Unified_id 对写入数据进行排序,然后按 Unified_id 对 zorder 进行排序。我可以确保每个表都被读取时

执行者 内容
1 借出:{1,2,3,…} 收藏:{1,2,3,…}
2 借出:{5000,5001,...} 收藏:{5000,5001,...}
8 借出:{12000,12001} 收藏:{12000,12001}

这样当查询像

select * 
  from loan
 inner
  join collections
    on loan.unified_id = collections.unified_id

满足该条件的所有行都已经在同一个执行器上,不需要进行额外的排序?

编辑:我当然找到了这个答案 - 如何控制 RDD 分区的首选位置?。但令人担忧的是,以 delta 形式读取,然后转换为 rdd 以强制分区位置,然后再次转换将达不到我所追求的减少开销的目的。

sql apache-spark databricks aws-databricks
1个回答
0
投票

在 Spark 中处理大型数据集时,优化性能变得至关重要。实现此目的的一种方法是仔细组织数据的存储和处理方式。假设您有几个大表,例如您提到的 Loan 和 Collection 表,每个表都有一个唯一的整数 ID。这些 ID 对于有效连接数据至关重要。现在,您面临的问题是运行时间长,通常会受到洗牌和排序步骤的瓶颈。但是有商店!通过明智地选择分区和最初写入数据的方式,您有可能避开这些瓶颈。想法如下:与其让 Spark 在各处对数据进行洗牌和排序,为什么不在写入数据时预先组织它呢?所以,假设您决定根据顺序 ID 将数据划分为 100 万个块。然后,当你写入数据时,你按照统一的ID对其进行排序,并使用一种称为zordering的技术来进一步优化排列。这确保了相关数据块存储在一起。这在实践中意味着什么?好吧,我们以从 Loan 和 Collection 表中查询数据为例。当 Spark 读取这些表时,连接操作所需的数据很可能已经位于同一个分区中,甚至可能位于同一个执行器上。因此,当您运行查询来连接 Loan 和 Collection 表时,Spark 没有花时间整理数据以使连接发生。由于您的分区和排序策略,它已经设置得很好。现在,关于您对转换数据类型的开销以及可能导致优化工作失败的担忧:您的谨慎是绝对正确的。但事情是这样的:您可以直接使用 Spark 的 DataFrame API 与 Delta Lake 来实现所有这些。通过将 DataFrame 转换与 Delta Lake 结合使用,您可以对数据进行分区和排序,而无需额外的转换。这意味着您可以在不牺牲效率的情况下获得性能优势。本质上,通过预先组织数据并利用 Spark 的内置优化功能,您可以显着提高 Spark 作业的性能,而不会增加不必要的复杂性。这一切都是为了从一开始就为自己的成功做好准备。

© www.soinside.com 2019 - 2024. All rights reserved.