如果我在[a,b,c]
中有df1
列和[a,b,c]
中有df2
列,并且还有d
列,则在两个地方d=concat_ws('_', *[a,b,c])
之间存在性能差异
df1.join(df2, [a,b,c])
df1.join(df2, d)
?
答案 0 :(得分:1)
不能以是或否回答问题,因为答案取决于数据框的详细信息。
联接的性能在很大程度上取决于以下问题:执行联接需要多少改组。如果联接的两侧都被同一列划分,联接将更快。通过查看联接的执行计划,您可以看到分区的效果。
我们用列df1
,df2
,a
和b
创建两个DataFrames c
和d
:
val sparkSession = ...
sparkSession.conf.set("spark.sql.autoBroadcastJoinThreshold", -1)
import sparkSession.implicits._
val cols = Seq("a","b","c")
def createDf = (1 to 3).map(i => (i,i,i)).toDF(cols:_*).withColumn("d", concat_ws("_", cols.map(col):_*))
val df1 = createDf
val df2 = createDf
df1
和df2
看起来都一样:
+---+---+---+-----+
| a| b| c| d|
+---+---+---+-----+
| 1| 1| 1|1_1_1|
| 2| 2| 2|2_2_2|
| 3| 3| 3|3_3_3|
+---+---+---+-----+
当我们按列d
对两个DataFrame进行分区并将该列用作连接条件时
df1.repartition(4, col("d")).join(df2.repartition(4, col("d")), "d").explain()
我们得到执行计划
== Physical Plan ==
*(3) Project [d#13, a#7, b#8, c#9, a#25, b#26, c#27]
+- *(3) SortMergeJoin [d#13], [d#31], Inner
:- *(1) Sort [d#13 ASC NULLS FIRST], false, 0
: +- Exchange hashpartitioning(d#13, 4)
: +- LocalTableScan [a#7, b#8, c#9, d#13]
+- *(2) Sort [d#31 ASC NULLS FIRST], false, 0
+- ReusedExchange [a#25, b#26, c#27, d#31], Exchange hashpartitioning(d#13, 4)
通过d
对两个DataFrame进行分区,但通过a
,b
和c
进行联接
df1.repartition(4, col("d")).join(df2.repartition(4, col("d")), cols).explain()
导致执行计划
== Physical Plan ==
*(3) Project [a#7, b#8, c#9, d#13, d#31]
+- *(3) SortMergeJoin [a#7, b#8, c#9], [a#25, b#26, c#27], Inner
:- *(1) Sort [a#7 ASC NULLS FIRST, b#8 ASC NULLS FIRST, c#9 ASC NULLS FIRST], false, 0
: +- Exchange hashpartitioning(a#7, b#8, c#9, 200)
: +- Exchange hashpartitioning(d#13, 4)
: +- LocalTableScan [a#7, b#8, c#9, d#13]
+- *(2) Sort [a#25 ASC NULLS FIRST, b#26 ASC NULLS FIRST, c#27 ASC NULLS FIRST], false, 0
+- ReusedExchange [a#25, b#26, c#27, d#31], Exchange hashpartitioning(a#7, b#8, c#9, 200)
比第一个计划多Exchange hashpartitioning
个。在这种情况下,a
,b
,c
的联接会更慢。
另一方面,如果数据帧按a
,b
和c
进行分区,则联接按a
,b
,{{1} }比c
的加入要快。
答案 1 :(得分:1)
我怀疑没有连接的连接会更快,因为仅散列各个字符串而不是连接然后进行散列可能更便宜。前者涉及较少的需要GC的Java对象,但这并不是完整的答案。
请注意,这可能不是查询的性能限制步骤,因此任何一种方法都将同样快。当涉及到性能调整时,最好进行测试而不是在没有数据的情况下进行猜测。
也如上所述,如果输入数据已经正确分区,则使列保持未连接状态将使优化器有机会消除联接上的交换。
df1.join(df2, [a,b,c])
df1.join(df2, d)