我一直在最近的Spark SQL 2.3.0-SNAPSHOT版本中探索查询优化,并注意到了语义相同查询的不同物理计划。
假设我必须计算以下数据集中的行数:
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
二进制格式body 计划就这么简单。
我的推理正确吗?如果是这样,如果我从外部数据源(例如文件,JDBC,Kafka)读取数据集,答案会有所不同吗?
主要问题是要考虑一个查询是否比其他查询更有效的因素(在此示例中)?
其他执行计划的完整性。
数量
q.collect.size
q.rdd.count
最佳答案
我对val q = spark.range(100000000)
做了一些测试:
q.count
:〜50毫秒q.collect.size
:一分钟左右后我停止了查询... q.rdd.count
:约1100毫秒q.queryExecution.toRdd.count
:〜600毫秒一些解释:
到目前为止,选项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。在没有整个阶段代码生成的情况下,速度差不多。
关于performance - 如何知道哪个计数查询最快?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43843470/