由于数据分布偏差,此Spark SQL查询的性能很差:
select c.*, coalesce(
sum(revenue)
OVER (PARTITION BY cid, pid, code
ORDER BY (cTime div (1000*3600))
RANGE BETWEEN 336 PRECEDING and 1 PRECEDING), 0L) as totalRevenue
from records c
我在SparkUI中看到,如果我增加扫描范围,单个任务堆栈和群集就会失败。
我在AWS EMR上使用Yarn,使用Spark 2.2.0
我如何克服这个问题? 谢谢
答案 0 :(得分:1)
我只能推荐几种方法来缓解你的调查条件。我实际上会尝试两种不首先处理偏斜的方法:
原因是至少在我看来你的数据基本上是偏斜的。如果您开始重新整形数据以解决当前数据形状的特定方式的偏斜,那么您将面临维护困难,因为数据的形状可能会随着时间的推移而变化。在我看来,至少你希望尽可能保留查询的最直接实现,并且只有在遇到SLA违规问题时才能以编程方式优化偏差问题等。
如果这些不起作用,那么您可以尝试直接解决偏差问题。 一种简单的方法是创建第三列,该列由随机数填充,用于已知有问题的列值。使用它作为关键点,对其进行一次求和操作,然后移除额外随机列的第二次传递。或者,您可以执行两个查询并将它们连接起来:一个用于偏斜数据的随机数(必须仍然在两次传递中处理),另一个用于无问题数据的未更改查询。
编辑 - 计算两帧的部分和
这里基本上有用的观察是加法是可交换的和联想的。我基于随机数的原始提案不会起作用,但这样做。基本上,您想要在几个部分中计算所需帧的部分和。最简单的方法可能是作为一组范围(为简单起见,这里使用了两个):
create temporary table partial_revenue_1 as select c.*, coalesce(
sum(revenue)
OVER (PARTITION BY cid, pid, code
ORDER BY (cTime div (1000*3600))
RANGE BETWEEN 336 PRECEDING and 118 PRECEDING), 0L) as partialTotalRevenue
from records c
create temporary table partial_revenue_2 as select c.*, coalesce(
sum(revenue)
OVER (PARTITION BY cid, pid, code
ORDER BY (cTime div (1000*3600))
RANGE BETWEEN 117 PRECEDING and 1 PRECEDING), 0L) as partialTotalRevenue
from records c
create temporary table combined_partials as select * from
partial_reveneue_1 union all select * from partial_revenue_2
select sum(partialTotalRevenue), first(c.some_col) ... from
combined_partials c group by cid, pid, code
请注意,您需要使用first
聚合函数来剔除您将从select *
表上的早期records
操作中获得的重复字段。不要担心,这样会很好,因为两个值来自同一张桌子。