我正在使用spark sql在镶木地板数据源上运行一些聚合查询。
我的实木复合地板数据源包括一个具有以下列的表:id int,time timestamp,location int,counter_1 long,counter_2 long,...,counter_48。总数据大小约为887 MB。
我的spark版本是2.4.0。我在一台计算机(4核,16G内存)上运行一个主机和一个从机。
使用spark-shell,我运行了spark命令:
spark.time(spark.sql("SELECT location, sum(counter_1)+sum(counter_5)+sum(counter_10)+sum(counter_15)+sum(cou
nter_20)+sum(counter_25)+sum(counter_30)+sum(counter_35 )+sum(counter_40)+sum(counter_45) from parquet.`/home/hungp
han227/spark_data/counters` group by location").show())
执行时间为17秒。
第二次我运行类似的命令(仅更改列):
spark.time(spark.sql("SELECT location, sum(counter_2)+sum(counter_6)+sum(counter_11)+sum(counter_16)+sum(cou
nter_21)+sum(counter_26)+sum(counter_31)+sum(counter_36 )+sum(counter_41)+sum(counter_46) from parquet.`/home/hungp
han227/spark_data/counters` group by location").show())
执行时间约为3s。
我的第一个问题是:为什么它们不同?我知道由于拼花格式,这不是数据缓存。是重用查询计划之类的东西吗?
我做了另一个测试:第一个命令是
spark.time(spark.sql("SELECT location, sum(counter_1)+sum(counter_5)+sum(counter_10)+sum(counter_15)+sum(cou
nter_20)+sum(counter_25)+sum(counter_30)+sum(counter_35 )+sum(counter_40)+sum(counter_45) from parquet.`/home/hungp
han227/spark_data/counters` group by location").show())
执行时间为17秒。
在第二个命令中,更改聚合函数:
spark.time(spark.sql("SELECT location, avg(counter_1)+avg(counter_5)+avg(counter_10)+avg(counter_15)+avg(cou
nter_20)+avg(counter_25)+avg(counter_30)+avg(counter_35 )+avg(counter_40)+avg(counter_45) from parquet.`/home/hungp
han227/spark_data/counters` group by location").show())
执行时间约为5s。
我的第二个问题是:为什么第二个命令比第一个命令快,但是执行时间差却比第一个场景小?
最后,我遇到了与上述情况有关的问题:大约有200个公式,例如:
formula1 = sum(counter_1)+sum(counter_5)+sum(counter_10)+sum(counter_15)+sum(cou
nter_20)+sum(counter_25)+sum(counter_30)+sum(counter_35 )+sum(counter_40)+sum(counter_45)
formula2 = avg(counter_2)+avg(counter_5)+avg(counter_11)+avg(counter_15)+avg(cou
nter_21)+avg(counter_25)+avg(counter_31)+avg(counter_35 )+avg(counter_41)+avg(counter_45)
我必须经常运行以下格式:
select formulaX,formulaY, ..., formulaZ from table where time > value1 and time < value2 and location in (value1, value 2...) group by location
我的第三个问题是:是否有必要优化性能(一次使用的查询如果将来再次使用应该更快)?火花会优化自身还是我必须编写一些代码,更改配置?
答案 0 :(得分:2)
这称为Exchange重用。当Spark运行改组(即聚合,联接)时,它会将改组数据的副本存储在本地工作节点上,以供潜在重用。这是一种内部控制的行为,不能受到最终用户的直接影响。如果发现自己一直在重复使用数据的特定部分(或查询结果),则可以考虑使用cache()显式地缓存它。但是,请记住,尽管这使Spark可以重用缓存的结果以提高潜在的查询性能(并且仅当您的缓存查询的分析器计划与您的新查询匹配时),但是过度使用CACHE可能会导致很多其他性能问题。 / p>
一个不好的例子是,当您的数据集很大时,可能会导致磁盘溢出问题。也就是说,数据集无法容纳到群集的可用内存中,需要将其写入速度较慢的硬盘。
另一个不好的例子是当您的查询仅需要访问缓存数据的子集时。通过在内存中缓存整个数据集,Spark被迫执行完整的内存表扫描。与完全不使用缓存相反,这不仅浪费资源,而且导致查询性能降低。
最好的办法是尝试使用一些您自己的示例查询尝试并出错,查看Spark UI并检查是否存在磁盘溢出迹象或大量输入数据扫描。
每种查询/数据组合都是唯一的,因此您需要进行一些试验,以找到适合自己工作负载的最佳性能调整方法。
答案 1 :(得分:0)
进行聚合火花时会创建所谓的随机文件。如果运行两次相同的查询,它将重复使用随机存储在工作程序fs上的随机文件。不幸的是,您不能依靠它们始终存在,因为最终文件处理程序会被gc'd处理。如果您要在同一个数据集上运行10个查询,请对其进行缓存或使用数据块。