当我像这样使用左连接连接两个数据帧时:
df1.join(broadcast(df2), $"id" === $"id1" || $"id2" === $"id3", "left")
如果没有
$"id2" === $"id3"
,它执行得非常快,但是当两个条件都存在时,它会变得 BroadcastNestedLoopJoin
并且变得非常非常慢。
有什么想法可以改进吗?
BroadcastNestedLoopJoin 表示嵌套 for 循环来连接数据帧。它总是会降低性能。
您可以尝试以下解决方案吗:
val resultPart1 = df1.join(broadcast(df2), $"id" === $"id1", "left")
val resultPart2 = df1.join(broadcast(df2), $"id2" === $"id3", "left")
val resultDF = resultPart1.unionByName(resultPart2)
Union 导致执行器之间的数据零洗牌。因此产生更快的结果
以 Spark 3.2 为例。
Spark 将委托给 5 种可用的加入策略之一。 在你的情况下,只有当你有一个等连接时,它才能使用广播哈希连接(BHJ)。
使用析取谓词(如
$"id" === $"id1" || $"id2" === $"id3"
)的连接条件是非等值连接。
使用连接谓词的连接条件
predicate1 AND predicate2 AND ..
是等值连接。
为了获得 BHJ,您可以委托给多个等连接。
df1
.join(broadcast(df2), $"id" === $"id1", "left")
.join(broadcast(df2), $"id2" === $"id3", "left")
然后在查询计划中验证两个连接引用相同的广播数据并使用广播哈希连接。