添加链接描述
谓词下推就是将查询的过滤条件尽可能下沉到数据源,减少对无关数据的读入。Spark在生成执行计划时会进行谓词下推的优化,对于内连接而言,过滤条件写在join中或者join后并没有差异,但是对于外连接,会存在不能谓词下推的情况。
参考:谓词下推介绍
COUNT DISTINCT实现原理、spark sql多维分析优化
中间数据量指的是Spark任务在计算过程中产生的数据量,也就是RDD的数据量。常见的两种导致数据膨胀的逻辑便是count(distinct )和grouping sets( )。数据膨胀是空间换时间的一种方式,适宜数据量小的情况。
** 1. count(distinct):** 对于count(distinct)带来的数据膨胀,我们可以采用size+collect_set的方法来进行优化。size(collect_set())实际上是依赖集合的数据结构进行去重,因此不会引起数据膨胀。
-- 替换前
count(distinct sku_id) as sku_num,
-- 替换后
size(collect_set(sku_id)) as sku_num,
**2.grouping sets:**建议在做grouping sets,把数据提前汇总一次,仅保留需要的维度和指标,尽量做到输入最少的数据。
select count(distinct a) as a_num,
count(distinct b) as b_num,
count(distinct c) as c_num,
count(distinct d) as d_num,
count(distinct e) as e_num,
count(distinct f) as f_num
from result
-- 拆分后
select count(distinct a) as a_num,
count(distinct b) as b_num,
count(distinct c) as c_num,
null as d_num,
null as e_num,
null as f_num
from result
union all select null as a_num,
null as b_num,
null as c_num,
count(distinct d) as d_num,
count(distinct e) as e_num,
count(distinct f) as f_num
from result
如果我们在任务中多次使用该子查询,就会导致子查询被重复执行多次。
解决方法就是将表cache到内存(数据量较小)或创建临时表(数据量较大)。在分区任务创建临时表时,建议临时表名带上时间变量的参数(如:‘tmp_table’+‘$now.datekey’),避免并行重导时产生表名冲突。
Broadcast Hash Join原理:先将小表拉到driver端,再把小表的数据广播到Spark的所有Executor端,然后在每个Executor端进行小表和大表的join,实现了map端的join操作,从而避免了shuffle。我们可以通过以下两种方式来实现Broadcast Hash Join。
select /*+ MAPJOIN(b) */
a.key,
b.value
from res1 a
join res2 b
on a.key=b.key
某个stage执行时间很长,但是stage内并行的task数量很少。
1、读文件优化
仅读文件优化,调整读文件并行度参数。
set spark.hadoop.hive.exec.orc.split.strategy=ETL;
set spark.hadoop.mapreduce.input.fileinputformat.split.maxsize=100663296; -- 调小该数值
set spark.hadoop.mapreduce.input.fileinputformat.split.minsize=100663296;
如果读文件后还有其他操作,导致执行时间长,那么在读文件后进行重分区,将读文件和其他RDD操作划分为不同stage。
1)全局增加分区
set spark.sql.adaptive.shuffle.targetPostShuffleInputSize=5592405;(数值需根据任务情况自行调整,减少该数值)
(全局增加分区,可能带来不必要的资源开销,也有可能造成小文件过多的情况)
前提是设置set spark.sql.shuffle.partition=true
2)局部增加分区(建议)
在shuffle前增加 distribute by语句,进行强制分区
参数解释:
spark.sql.adaptive.enabled:是否开启调整partition功能,如果开启,spark.sql.shuffle.partitions设置的partition可能会被合并到一个reducer里运行。平台默认开启,同时强烈建议开启。理由:更好利用单个executor的性能,还能缓解小文件问题。
spark.sql.adaptive.shuffle.targetPostShuffleInputSize:和spark.sql.adaptive.enabled配合使用,当开启调整partition功能后,当mapper端两个partition的数据合并后数据量小于targetPostShuffleInputSize时,Spark会将两个partition进行合并到一个reducer端进行处理。平台默认为67108864(64M),用户可根据自身作业的情况酌情调整该值。当调大该值时,一个reduce端task处理的数据量变大,最终产出的数据,存到HDFS上的文件也变大。当调小该值时,相反。
2、计算优化-单task处理任务较多
set spark.sql.adaptive.shuffle.targetPostShuffleInputSize=5592405;(数值需根据任务情况自行调整,减少该数值;全局增加分区,可能带来不必要的资源开销,也有可能造成小文件过多的情况)
3、写文件优化
增加写文件并行度:如distribute by dt, abs(hash(id) % 10) 。尽可能不要用rand函数。
现象:绝大多数task执行得都非常快,但个别task执行极慢
原因:shuffle时某些key的数量特别大,导致数据分配不均,少量的task处理了绝大部分数据量
优化方法:转化map join、过滤无效极值、随机膨胀等
数据倾斜问题