深入浅出数据仓库中SQL性能优化之Hive篇忽略元数据末尾添加者:邓昌甫/GFZQ,最后更新者:邓昌甫/GFZQ于九月24,2015回到原数据开始处摘要:Hive查询生成多个mapreducejob,—个mapreducejob又有map,reduce,spill,shuffle,sort等多个阶段,所以针对hive查询的优化可以大致分为针对MR中单个步骤的优化,针对MR全局的优化以及针对整个查询的优化。一个Hive查询生成多个MapReduceJob,—个MapReduceJob又有Map,Reduce,Spill,Shuffle,Sort等多个阶段,所以针对Hive查询的优化可以大致分为针对MR中单个步骤的优化(其中又会有细分),针对MR全局的优化,和针对整个查询(多MRJob)的优化,下文会分别阐述。在开始之前,先把MR的流程图帖出来(摘自Hadoop权威指南),方便后面对照。另外要说明的是,这个优化只是针对Hive0.9版本,而不是后来Hortonwork发起Stinger项目之后的版本。相对应的Hadoop版本是1.x而非2.x。Map阶段的优化(Mapphase)Map阶段的优化,主要是确定合适的Map数。那么首先要了解Map数的计算公式:[js]viewplaincopy1.num_Map_tasks=max[${Mapred.min.split.size},2.min(${dfs.block.size},${Mapred.max.split.size})]•Mapred.min.split.size指的是数据的最小分割单元大小。•Mapred.max.split.size指的是数据的最大分割单元大小。•dfs.block.size指的是HDFS设置的数据块大小。[js]viewplaincopy1.Hive>setdfs.block.size;2.dfs.block.sizeisundefined所以实际上只有Mapred.min.split.size和Mapred.max.split.size这两个参数(本节内容后面就以min和max指代这两个参数)来决定Map数量。在Hive中min的默认值是1B,max的默认值是256MB:[js]viewplaincopy1.Hive>setMapred.min.split。size;2.Mapred.min.split.size=13.Hive>setMapred.max.split。size;4.Mapred.max.split.size=256000000所以如果不做修改的话,就是1个Maptask处理256MB数据,我们就以调整max为主。通过调整max可以起到调整Map数的作用,减小max可以增加Map数,增大max可以减少Map数。需要提醒的是,直接调整Mapred.Map.tasks这个参数是没有效果的。调整大小的时机根据查询的不同而不同,总的来讲可以通过观察Maptask的完成时间来确定是否需要增加Map资源。如果Maptask的完成时间都是接近1分钟,甚至几分钟了,那么往往增加Map数量,使得每个Maptask处理的数据量减少,能够让Maptask更快完成;而如果Maptask的运行时间已经很少了,比如10-20秒,这个时候增加Map不太可能让Maptask更快完成,反而可能因为Map需要的初始化时间反而让Job总体速度变慢,这个时候反而需要考虑是否可以把Map的数量减少,这样可以节省更多资源给其他Job。Reduce阶段的优化(Reducephase)这里说的Reduce阶段,是指前面流程图中的Reducephase(实际的Reduce计算)而非图中整个Reducetask。Reduce阶段优化的主要工作也是选择合适的Reducetask数量,跟上面的Map优化类似。与Map优化不同的是,Reduce优化时,可以直接设置Mapred。Reduce□tasks参数从而直接指定Reduce的个数。当然直接指定Reduce个数虽然比较方便,但是不利于自动扩展。Reduce数的设置虽然相较Map更灵活,但是也可以像Map—样设定一个自动生成规则,这样运行定时Job的时候就不用担心原来设置的固定Reduce数会由于数据量的变化而不合适。Hive估算Reduce数量的时候,使用的是下面的公式:[js]viewplaincopy1.num_Reduce_tasks=min[${Hive.exec.Reducers.max},2.(${input.size}/${Hive.exec.Reducers.bytes.per.Reducer})]也就是说,根据输入的数据量大小来决定Reduce的个数,默认Hive.exec.Reducers.bytes.per.Reducer为1G,而且Reduce个数不能超过一个上限参数值,这个参数的默认取值为999。所以我们可以调整Hive.exec.Reducers.bytes.per.Reducer来设置Reduce个数。设置Reduce数同样也是根据运行时间作为参考调整,并且可以根据特定的业务需求、工作负载类型总结出经验,所以不再赘述。Map与Reduce之间的优化(Spill,copy,Sortphase)Mapphase和Reducephase之间主要有3道工序。首先要把Map输出的结果进行排序后做成中间文件,其次这个中间文件就能分发到各个Reduce,最后R...