一个Hive查询生成多个map reduce job,一个map reduce job又有map,reduce,spill,shuffle,sort等多个阶段,因此针对hive查询的优化能够大体分为针对M/R中单个步骤的优化,针对M/R全局的优化,和针对整个查询(多M/R job)的优化。算法
Map阶段的优化,主要是肯定合适的map数。那么首先要了解map数也就是切 片的计算公式,即:sql
块大小和切片的最大值求的最小值和最大切片求最大值。app
在hive中min的默认值是1B,max的默认值是256MB分布式
num_map_tasks = max[${mapred.min.split.size}, min(${dfs.block.size}, ${mapred.max.split.size})]oop
通过以上的分析,在设置map个数的时候,能够简单的总结为如下几点:
(1)若是想增长map个数,则设置mapred.map.tasks 为一个较大的值。
(2)若是想减少map个数,则设置mapred.min.split.size 为一个较大的值。
(3)若是输入中有不少小文件,依然想减小map个数,则须要将小文件merger为大文件,而后使用准则2。性能
Reduce阶段的优化优化
是指前面流程图中的reduce phase(实际的reduce计算)而非图中整个reduce task。Reduce阶段优化的主要工做也是选择合适的reduce task数量,跟上面的map优化相似。spa
reduce优化时,能够直接设置mapred.reduce.tasks参数从而直接指定reduce的个数。线程
Map与Reduce之间的优化调试
所谓map和reduce之间,主要有3道工序。首先要把map输出的结果进行排序后作成中间文件,其次这个中间文件就能分发到各个reduce,最后reduce端在执行reduce phase以前把收集到的排序子文件合并成一个排序文件。
第一个阶段中,因为内存不够,数据可能没办法在内存中一次性排序完成,那么就只能把局部排序的文件先保存到磁盘上,这个动做叫spill,而后spill出来的多个文件能够在最后进行merge。若是发生spill,能够经过设置io.sort.mb来增大mapper输出buffer的大小,避免spill的发生。另外合并时能够经过设置io.sort.factor来使得一次性可以合并更多的数据。调试参数的时候,一个要看spill的时间成本,一个要看merge的时间成本,还须要注意不要撑爆内存(io.sort.mb是算在map的内存里面的)。
关于文件从map端copy到reduce端,默认状况下在5%的map完成的状况下reduce就开始启动copy,这个有时候是很浪费资源的,因为reduce一旦启动就被占用,一直等到map所有完成,收集到全部数据才能够进行后面的动做,因此咱们能够等比较多的map完成以后再启动reduce流程,这个比例能够经过mapred.reduce.slowstart. completed.maps去调整,他的默认值就是5%。若是以为这么作会减慢reduce端copy的进度,能够把copy过程的线程增大。
文件格式的优化
文件格式方面有两个问题,一个是给输入和输出选择合适的文件格式,另外一个则是小文件问题。小文件问题在目前的hive环境下已经获得了比较好的解决,hive的默认配置中就能够在小文件输入时自动把多个文件合并给1个map处理(固然,若是能直接读取大文件更好),输出时若是文件很小也会进行一轮单独的合并,因此这里就不专门讨论了。
关于文件格式,Hive中目前主要是3种,textfile,sequencefile和rcfile。整体上来讲,rcfile的压缩比例和查询时间稍好一点,因此推荐使用。
Job总体优化
Job执行模式(本地执行v.s.分布式执行)、索引、Join算法、以及数据倾斜
Job执行模式
Hadoop的map reduce job能够有3种模式执行,即本地模式,伪分布式,还有真正的分布式。
可是实际上对于处理数据量很是小的job,直接启动分布式job会消耗大量资源,而真正执行计算的时间反而很是少。这个时候就应该使用本地模式执行mr job,这样执行的时候不会启动分布式job,执行速度就会快不少。
设置执行模式的主要参数有三个,一个是hive.exec.mode.local.auto,把他设为true就可以自动开启local mr模式。可是这还不足以启动local mr,输入的文件数量和数据量大小必需要控制,这两个参数分别为hive.exec.mode.local.auto.tasks.max和hive.exec.mode.local.auto.inputbytes.max,默认值分别为4和128MB,即默认状况下,map处理的文件数不超过4个而且总大小小于128MB就启用local mr模式。
Join算法
当两个表中有一个是小表的时候,就能够考虑用map join了,由于小表复制的代价会好过大表shuffle的代价。使用map join的配置方法有两种,一种直接在sql中写hint,语法是/*+MAPJOIN (tbl)*/,其中tbl就是你想要作replication的表。另外一种方法是设置hive.auto.convert.join = true,这样hive会自动判断当前的join操做是否合适作map join,主要是找join的两个表中有没有小表。至于多大的表算小表,则是由hive.smalltable.filesize决定,默认25MB。可是在小表join大表的时候要考虑小表的记录的条目数,每一个条目数占200字节,有时候可能大概80M的小表它的实际占用空间是1G多,会撑爆内存
数据倾斜
group by形成的倾斜和join形成的倾斜须要分开看。group by形成的倾斜有两个参数能够解决,一个是hive.map.aggr,默认值已经为true,意思是会作map端的combiner。
另外一个参数是hive.groupby.skewindata。这个参数的意思是作reduce操做的时候,拿到的key并非全部相同值给同一个reduce,而是随机分发,而后reduce作聚合,作完以后再作一轮MR,拿前面聚合过的数据再算结果
SQL总体优化
在hive生成的多个job中,在有些状况下job之间是能够并行的,典型的就是子查询。当须要执行多个子查询union all或者join操做的时候,job间并行就可使用了。
设置job间并行的参数是hive.exec.parallel,将其设为true便可。默认的并行度最高为8,也就是容许sql中8个job并行。若是想要更高的并行度,能够经过hive.exec.parallel. thread.number参数进行设置,但要避免设置过大而占用过多资源。