我们假设我必须计算以下数据集中的行数:
val q = spark.range(1)
我可以按如下方式计算行数:
> q.count
> q.collect.size
> q.rdd.count
> q.queryExecution.toRdd.count
我最初的想法是它几乎是一个恒定的操作(肯定是由于本地数据集),它会以某种方式由Spark SQL优化并立即给出结果,尤其是. Spark SQL完全控制查询执行的第一个.
看了查询的物理计划后,我就相信最有效的查询将是最后一个:
q.queryExecution.toRdd.count
原因是:
>它避免了从InternalRow二进制格式反序列化行
>查询是代码
>只有一个单一阶段的工作
物理计划就这么简单.
我的推理是否正确?如果是这样,如果我从外部数据源(例如文件,JDBC,Kafka)读取数据集,答案会有所不同吗?
主要问题是,要考虑查询是否比其他查询更有效(在此示例中),需要考虑哪些因素?
其他执行计划是完整性的.
q.count
q.collect.size
q.rdd.count
我在val q = spark.range(100000000)上做了一些测试:> q.count:~50 ms
> q.collect.size:我在一分钟左右后停止了查询…
> q.rdd.count:~1100 ms
> q.queryExecution.toRdd.count:~600 ms
一些解释:
选项1是目前最快的,因为它使用部分聚合和整个阶段代码生成.整个阶段代码生成允许JVM变得非常聪明并进行一些激烈的优化(参见:https://databricks.com/blog/2017/02/16/processing-trillion-rows-per-second-single-machine-can-nested-loop-joins-fast.html).
选项2.只是缓慢并实现驱动程序上的所有内容,这通常是一个坏主意.
选项3.与选项4类似,但这首先将内部行转换为常规行,这非常昂贵.
选项4.如果没有整个阶段代码生成,您的速度会快得多.