Spark 3.0 之后,对Spark-SQL增加了三种join选项:SHUFFLE_HASH, SHUFFLE_MERGE , SHUFFLE_REPLICATE_NL。(原先只有BROADCAST 一种)
参考地址:https://github.com/apache/spark/pull/24164
SHUFFLE_HASH(Shuffle Hash Join):
根据关联key对数据进行分区,然后再进行join。
SHUFFLE_HASH会对左右两张表使用相同的分区方式,确保相同分区内数据的key都是相同的。
它遵循经典的map-reduce模式:
- 对两张表进行map操作。
- 使用关联的key作为map程序输出的key。
- 对输出的key进行分区,这样一来就可以确保相同key的两张表的数据会在一台机器(reduce)上。
- 在reducer 端对两张表进行join操作。
SHUFFLE_HASH适用于以下两种情况:
- 两张表中用于关联的key的数据必须均匀,不能有热点key。
- 两张表中用于关联的key的个数必须大于并行度。(如设置并行度为200,但只有20个key,那么有180个task都在空跑)
SHUFFLE_HASH可以用于处理大表join大表,但是由于需要重新分区,所以消耗的资源也比较多。
要想生效,必须将spark.sql.join.preferSortMergeJoin设为false,因为SortMergeJoin的优先级高于Shuffle Hash Join。
SHUFFLE_MERGE (SortMergeJoin):
从Spark 2.3开始,作为spark的默认的关联方式。比Shuffle Hash Join多了一步排序。使相同分区内的key进行关联时,不必全扫描另一张表的该分区的所有key。
Sort merge join的步骤为:
- 将两张表按照关联key重新分区。
- 将分区后的数据进行排序。
- 将排序后的数据,像拉链一样进行关联,如下图。
在大表join大表时,Sort merge join的性能要高于Shuffle Hash Join。
BroadCast Join(广播join)
顾名思义,就是大表关联小表时,将小表整张表广播至任务所在的所有机器上,使大表的数据不用在集群间移动,减小shuffle带来的计算成本。
广播join只适合其中一张表是小表的情况。
spark默认会将小于4MB(可以修改 spark.sql.autoBroadcastJoinThreshold 参数,目前我们设置的是50MB)的表广播出去,如果你不确定表是否小于这个值时,可以在SQL中使用 /*+ BROADCAST(表名) */ 指定广播的表名。
总结
经实践,在大表join大表的场景下,spark默认的SortMergeJoin方式性能高于Shuffle Hash Join方式,所以大表join大表无需指定join方式;
仅在大表join小表时使用 /*+ BROADCAST(表名) */ 指定广播的表名即可。