我创建了一个Spark Dataset[Long]
:
scala> val ds = spark.range(100000000)
ds: org.apache.spark.sql.Dataset[Long] = [id: bigint]
当我运行ds.count
时,它给了我0.2s
的结果(在4 Core 8GB机器上)。此外,它创建的DAG如下:
但是,当我跑ds.rdd.count
时,它给了我4s
(同一台机器)的结果。但它创建的DAG如下:
所以,我的怀疑是:
ds.rdd.count
只创建了一个阶段而ds.count
正在创建两个阶段?ds.rdd.count
只有一个阶段时,为什么它比ds.count
有两个阶段要慢?答案 0 :(得分:8)
为什么ds.rdd.count只创建一个阶段,而ds.count创建了两个阶段?
这两项计数实际上都是两步操作。不同之处在于,ds.count
的情况下,最终聚合由其中一个执行者执行,而ds.rdd.count
aggregates the final result on the driver则执行,因此此步骤不会反映在DAG中:
此外,当
ds.rdd.count
只有一个阶段时,为什么它更慢
同上。此外ds.rdd.count
必须初始化(以及后来的垃圾收集)1亿个Row
个对象,这几乎不是免费的,可能占据了这里的大部分时间差异。
最后range
- 类似的对象不是一个很好的基准测试工具,除非非常谨慎使用。根据上下文计算,超出范围可以表示为恒定时间操作,即使没有明确的优化也可以非常快(例如参见spark.sparkContext.range(0, 100000000).count
),但不能反映实际工作负载的性能。