连接两个表

时间:2017-11-30 09:06:46

标签: apache-spark hive apache-spark-sql

我有两个很大的Hive表,我想用spark.sql加入。我们假设我们有表1和表2,表1中有500万行,表2中有7000万行。表格采用活泼的格式并存储在Hive中作为镶木地板文件。

我想加入它们并在某些列上进行一些聚合,让我们说在计算所有行和列的平均值(例如doubleColumn)时使用两个条件进行过滤(比如col1,col2)。

注意:我在一台机器上进行测试安装(尽管它非常强大)。我希望群集中的性能可能会有所不同。

我的第一次尝试是使用spark sql,如:

 val stat = sqlContext.sql("select count(id), avg(doubleColumn) " +
                              " FROM db.table1 as t1 JOIN db.table2 " +
                              " ON t1.id = t2.id " + 
                              " WHERE col1 = val1 AND col2 = val2").collect

不幸的是,即使我为每个执行程序和驱动程序提供至少8 GB的内存,这个运行也很差,大约5分钟。我还尝试使用数据帧语法并尝试首先过滤行,并仅选择特定列以获得更好的选择性,如:

//Filter first and select only needed column
val df = spark.sql("SELECT * FROM db.tab1")
val tab1= df.filter($"col1" === "val1" && $"col2" === "val2").select("id")

val tab2= spark.sql("SELECT id, doubleColumn FROM db.tab2")
val joined = tab1.as("d1").join(tab2.as("d2"), $"d1.id" === $"d2.id") 

//Take the aggregations on the joined df
import org.apache.spark.sql.functions;

joined.agg(
   functions.count("id").as("count"),
   functions.avg("doubleColumn").as("average")
).show();

但这并没有显着的性能提升。如何提高加入性能?

  • 执行此spark.sql或dataframe语法的最佳方法是什么?

  • 给予更多执行者或记忆会有帮助吗?

  • 我应该使用缓存吗? 我缓存了两个数据帧tab1,tab2和join聚合都有显着的收获,但我认为缓存我的数据帧是不切实际的,因为我们对并发感兴趣,许多用户同时询问一些分析查询。

  • 没有什么可做的,因为我在单个节点上工作,当我进入集群上的生产环境时,我的问题会消失吗?

加分问题:我尝试使用Impala进行此查询,它确实耗时约40秒,但它比spark.sql更好。 Impala如何比火花更好?!

2 个答案:

答案 0 :(得分:5)

  

执行此spark.sql或dataframe语法的最佳方法是什么?

没有任何区别。

  

给予更多执行者或记忆会有帮助吗?

仅当问题不是由数据偏差引起并且您正确调整配置时才会发生。

  

我应该使用缓存吗?

如果多次重复使用输入数据,那么建议(如您已经确定的)性能方面是明智的。

  

没有什么可做的,因为我在单个节点上工作,当我进入集群上的生产环境时,我的问题会消失吗?

通常,单个节点上的性能测试完全没用。它错过了瓶颈(网络IO /通信)和优势(分摊磁盘I / O和资源使用)。

但是,您可以显着降低parallelsm(spark.sql.shuffle.partitionssql.default.parallelism和增加的输入分割大小。 Counterintuitiv Spark风格的并行性,专为分配负载而设计,在一台机器上比一项资产更容易承担责任。它依赖于shuffle(磁盘写入!)进行通信,使得与共享内存相比速度极慢,并且调度开销很大。

  

Impala如何比火花更好?!

因为它专为低延迟并发查询而设计。它不是Spark的目标(数据库与ETL框架)。

当你

  

因为我们对并发感兴趣,许多用户同时询问一些分析查询。

Spark听起来不是一个正确的选择。

答案 1 :(得分:1)

您可以更改配置,无论如何您都必须在大型群集上更改它们。我马上就能想到两件事。将spark.executor.cores设置为5,并根据内存,通过spark.executor.instancesspark.executor.memory提供更多执行程序和更多内存。您还可以通过某些列对蜂巢表进行分类和排序吗?如果你打开表,那么它将消除在加入表之前对表进行排序的需要。

如果在连接后缓存数据帧,也可能会更快,具体取决于催化剂处理聚合查询的方式。在查询结束后您也可以unpersist()但我同意GC可能不值得。

您无法使用SQL或scala dsl获得任何好处。两者都使用全阶段代码生成,因此它们基本相同。

Impala总是更快的一个原因是因为它永远不会担心复制,尽管有一个节点不应该那么麻烦但是在为复制预先设置数据和不需要之间可能没有优雅的分离火花复制。