最近在进行SQL优化工作,网上看了很多博客了解到MAPJOIN这一工具,本文主要是进行调研实践,原理过程复制大佬文章内容并进行了整理,注明了出处。
适用场景: 大表join一个或者多张小表,小表不超过8个,如果超过应该嵌套一层子查询,每个小表大小不超过25MB(这里应该指的是小表在内存中的大小,不是磁盘大小)。
原理过程:
(1)首先是本地客户端生成的Task A--MapReduce Local Task,将小表的数据Small Table Data读取到内存哈希表中,然后将哈希表序列化压缩为tar格式的磁盘文件HashTable Files,接着将该文件上传到分布式缓存Distributed Cache。
(2)再接着是Task C--没有reduce的MapReduce任务,该任务启动时会把上一步保存在分布式缓存中的tar文件拉取解压到每个Mapper任务所在的磁盘中,然后Mapper进一步将哈希表文件反序列化到内存,然后在顺序扫描大表数据Big Table Data时与内存中的小表数据join,避免在reduce阶段进行join。
注:观察过Spark任务执行过程的应该会发现任务运行时间比较长的阶段主要是shuffle和reduce,因此大部分调优主要是针对这两个阶段进行(从上一篇调优-入门中可以看到)。
实践过程:
数据情况:大表A大小386.2GB,小表b大小1.3MB,小表c大小189.8KB,小表d大小11.1KB。
资源使用:executor-cores=3,driver-memory=6G,executor-memory=6G,maxExecutors=200,shuffle.partitions=1800,output.files=1530。
使用方式:select /+ MAPJOIN(b,c,d)/ A.x,A...,b.x,c.x,d.x from A inner join b on A.x1 = b.x1 left join c on A.x2 = c.x2 left join d on A.x3 = d.x3
任务运行:
在没有使用MAPJOIN时,任务运行出现数据倾斜的情况,有一个Task报错:TaskMemoryManager: error while calling spill() on org.apache.spark.shuffle.sort.ShuffleExternalSorter@6aef6a74。
使用MAPJOIN后任务运行成功,并且运行阶段减少,猜测没使用该参数时每次大表A分别与小表b、c及d分别做join操作才多了三个阶段。
总结:MAPJOIN在Spark SQL中使用符合条件的情况下能大幅缩短任务运行时间,并且减少数据倾斜情况的发生。
参考:blog.csdn.net/xiaozhaoshi… blog.csdn.net/QiSorry/art… blog.csdn.net/sinat_37574…