Spark-SQL中DISTRIBUTE BY和Shuffle之间的区别

时间:2019-08-09 11:49:59

标签: python apache-spark apache-spark-sql pyspark-sql

我试图了解Distribute by子句,以及如何在Spark-SQL中使用它来优化Sort-Merge Joins

据我了解,Spark Sql优化器将基于联接键(随机播放阶段)分配(联接的)两个参与表的数据集,以将相同键共同定位在同一分区中。如果是这样,那么如果我们在sql中使用distribute by,那么我们也在做相同的事情。

那么可以以什么方式使用distribute by来改善联接性能?还是在加载过程中将数据写入磁盘时使用distribute by更好,这样以后使用该数据的查询就可以不必重新整理就可以从中受益?

能否请您通过一个真实的示例进行说明,以在Spark-SQL中使用distribute by/cluster by来调整联接?

1 个答案:

答案 0 :(得分:0)

让我尝试回答您问题的每个部分:

  

据我了解,Spark Sql优化器将基于联接键(随机播放阶段)分配(联接的)两个参与表的数据集,以将相同键共同定位在同一分区中。如果是这种情况,那么如果我们在sql中使用Distribution by,那么我们也在做相同的事情。

是的。

  

那么可以通过哪种方式分配以改善连接性能?

有时候,您的一个表已经被分发,例如,该表已存储在桶中,或者在通过同一键联接之前汇总了数据。在这种情况下,如果您还明确地对第二个表进行了重新分区(由...分配),则您将在连接的两个分支中实现相同的分区,并且Spark将不会在第一个分支中引起更多的混洗(有时称为单侧混洗) -free联接,因为改组将仅在联接的一个分支中发生-您在其中调用重新分区/分配。另一方面,如果您不显式地对另一个表进行分区,Spark将看到联接的每个分支具有不同的分区,因此它将对这两个分支进行重新排序。因此,在某些特殊情况下,调用重新分区(分配依据)可以为您节省一堆。

请注意,要进行此工作,您还需要在两个分支中实现相同数量的分区。因此,如果您要在键user_id上加入两个表,并且如果使用该键将第一个表存储到10个存储桶中,则需要通过相同的键将另一个表重新分区为10个分区,然后该联接将只有一个洗牌(在物理计划中,您可以看到在联接的一分支中将只有Exchange运算符)。

  

还是在通过加载过程将数据写入磁盘时使用“分发方式”更好,这样以后使用此数据的查询将不必通过重新整理就可以从中受益?

嗯,这实际上称为存储区(cluster by),它允许您预先对数据进行预混洗,然后每次读取数据并使用与存储区集相同的键将其合并(或聚合),它不会混洗。因此,是的,这是一种非常普遍的技术,您在保存数据时只需支付一次费用,然后在每次读取数据时就可以利用这些费用。