1. limit限制调整一般情况下Limit语句还是需要执行整个查询语句然后再返回部分结果。有一个配置属性可以开启避免这种情况---对数据源进行抽样。hive.limit.optimize.enabletrue --- 开启对数据源进行采样的功能 hive.limit.row.max.size --- 设置最小的采样容量 hive.limit.optimize.limit.file --- 设置最大的采样样本数缺点有可能部分数据永远不会被处理到2. JOIN优化1)将大表放后头Hive假定查询中最后的一个表是大表。它会将其它表缓存起来然后扫描最后那个表。因此通常需要将小表放前面或者标记哪张表是大表/*streamtable(table_name) */2). 使用相同的连接键当对3个或者更多个表进行join连接时如果每个on子句都使用相同的连接键的话那么只会产生一个MapReduce job。3). 尽量尽早地过滤数据减少每个阶段的数据量,对于分区表要加分区同时只选择需要使用到的字段。4). 尽量原子化操作尽量避免一个SQL包含复杂逻辑可以使用中间表来完成复杂的逻辑3. 本地模式有时hive的输入数据量是非常小的。在这种情况下为查询出发执行任务的时间消耗可能会比实际job的执行时间要多的多。对于大多数这种情况hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集执行时间会明显被缩短set hive.exec.mode.local.autotrue;当一个job满足如下条件才能真正使用本地模式 - 1.job的输入数据大小必须小于参数hive.exec.mode.local.auto.inputbytes.max(默认128MB) - 2.job的map数必须小于参数hive.exec.mode.local.auto.tasks.max(默认4) - 3.job的reduce数必须为0或者1可用参数hive.mapred.local.mem(默认0)控制child jvm使用的最大内存数。4.并行执行hive会将一个查询转化为一个或多个阶段包括MapReduce阶段、抽样阶段、合并阶段、limit阶段等。默认情况下一次只执行一个阶段。不过如果某些阶段不是互相依赖是可以并行执行的。set hive.exec.paralleltrue,可以开启并发执行。set hive.exec.parallel.thread.number16; //同一个sql允许最大并行度默认为8。会比较耗系统资源。5.strict模式对分区表进行查询在where子句中没有加分区过滤的话将禁止提交任务(默认nonstrict)set hive.mapred.modestrict;注使用严格模式可以禁止3种类型的查询1对于分区表不加分区字段过滤条件不能执行2对于order by语句必须使用limit语句3限制笛卡尔积的查询join的时候不使用on而使用where的6.调整mapper和reducer个数Map阶段优化map执行时间map任务启动和初始化的时间逻辑处理的时间。1.通常情况下作业会通过input的目录产生一个或者多个map任务。主要的决定因素有input的文件总个数input的文件大小集群设置的文件块大小(目前为128M, 可在hive中通过set dfs.block.size;命令查看到该参数不能自定义修改)2.举例a)假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块6个128m的块和1个12m的块从而产生7个map数 b)假设input目录下有3个文件a,b,c,大小分别为10m20m130m那么hadoop会分隔成4个块10m,20m,128m,2m,从而产生4个map数 即如果文件大于块大小(128m),那么会拆分如果小于块大小则把该文件当成一个块。3.是不是map数越多越好答案是否定的。如果一个任务有很多小文件远远小于块大小128m,则每个小文件也会被当做一个块用一个map任务来完成而一个map任务启动和初始化的时间远远大于逻辑处理的时间就会造成很大的资源浪费。而且同时可执行的map数是受限的。4.是不是保证每个map处理接近128m的文件块就高枕无忧了答案也是不一定。比如有一个127m的文件正常会用一个map去完成但这个文件只有一个或者两个小字段却有几千万的记录如果map处理的逻辑比较复杂用一个map任务去做肯定也比较耗时。针对上面的问题3和4我们需要采取两种方式来解决即减少map数和增加map数如何合并小文件减少map数假设一个SQL任务Select count(1) from popt_tbaccountcopy_mes where pt 2012-07-04 该任务的inputdir /group/p_sdo_data/p_sdo_data_etl/pt/popt_tbaccountcopy_mes/pt2012-07-04 共有194个文件其中很多是远远小于128m的小文件总大小9G正常执行会用194个map任务。Map总共消耗的计算资源SLOTS_MILLIS_MAPS 623,020 通过以下方法来在map执行前合并小文件减少map数set mapred.max.split.size100000000; set mapred.min.split.size.per.node100000000; set mapred.min.split.size.per.rack100000000; set hive.input.formatorg.apache.hadoop.hive.ql.io.CombineHiveInputFormat;再执行上面的语句用了74个map任务map消耗的计算资源SLOTS_MILLIS_MAPS333,500 对于这个简单SQL任务执行时间上可能差不多但节省了一半的计算资源。大概解释一下100000000表示100Mset hive.input.formatorg.apache.hadoop.hive.ql.io.CombineHiveInputFormat;这个参数表示执行前进行小文件合并前面三个参数确定合并文件块的大小大于文件块大小128m的按照128m来分隔小于128m,大于100m的按照100m来分隔把那些小于100m的包括小文件和分隔大文件剩下的进行合并,最终生成了74个块。如何适当的增加map数当input的文件都很大任务逻辑复杂map执行非常慢的时候可以考虑增加Map数 来使得每个map处理的数据量减少从而提高任务的执行效率。假设有这样一个任务Select data_desc, count(1), count(distinct id), sum(case when …), sum(case when ...), sum(…) from a group by data_desc如果表a只有一个文件大小为120M但包含几千万的记录如果用1个map去完成这个任务肯定是比较耗时的这种情况下我们要考虑将这一个文件合理的拆分成多个这样就可以用多个map任务去完成。set mapred.reduce.tasks10; create table a_1 as select * from a distribute by rand(123);这样会将a表的记录随机的分散到包含10个文件的a_1表中再用a_1代替上面sql中的a表则会用10个map任务去完成。每个map任务处理大于12M几百万记录的数据效率肯定会好很多。看上去貌似这两种有些矛盾一个是要合并小文件一个是要把大文件拆成小文件这点正是重点需要关注的地方根据实际情况控制map数量需要遵循两个原则使大数据量利用合适的map数使单个map任务处理合适的数据量。控制hive任务的reduce数1.Hive自己如何确定reduce数reduce个数的设定极大影响任务执行效率不指定reduce个数的情况下Hive会猜测确定一个reduce个数基于以下两个设定hive.exec.reducers.bytes.per.reducer每个reduce任务处理的数据量默认为1000^31G hive.exec.reducers.max每个任务最大的reduce数默认为999计算reducer数的公式很简单Nmin(参数2总输入数据量/参数1)即如果reduce的输入map的输出总大小不超过1G,那么只会有一个reduce任务如select pt,count(1) from popt_tbaccountcopy_mes where pt 2012-07-04 group by pt;/group/p_sdo_data/p_sdo_data_etl/pt/popt_tbaccountcopy_mes/pt2012-07-04 总大小为9G多因此这句有10个reduce2.调整reduce个数方法一调整hive.exec.reducers.bytes.per.reducer参数的值set hive.exec.reducers.bytes.per.reducer500000000; 500M select pt,count(1) from popt_tbaccountcopy_mes where pt 2012-07-04 group by pt; 这次有20个reduce3.调整reduce个数方法二set mapred.reduce.tasks 15; select pt,count(1) from popt_tbaccountcopy_mes where pt 2012-07-04 group by pt;这次有15个reduce4.reduce个数并不是越多越好同map一样启动和初始化reduce也会消耗时间和资源另外有多少个reduce,就会有多少个输出文件如果生成了很多个小文件 那么如果这些小文件作为下一个任务的输入则也会出现小文件过多的问题5.什么情况下只有一个reduce很多时候你会发现任务中不管数据量多大不管你有没有设置调整reduce个数的参数任务中一直都只有一个reduce任务其实只有一个reduce任务的情况除了数据量小于hive.exec.reducers.bytes.per.reducer参数值的情况外还有以下原因a)没有group by的汇总比如把select pt,count(1) from popt_tbaccountcopy_mes where pt 2012-07-04 group by pt; 写成 select count(1) from popt_tbaccountcopy_mes where pt 2012-07-04; 这点非常常见希望大家尽量改写。b)用了Order byc)有笛卡尔积通常这些情况下除了找办法来变通和避免我们暂时没有什么好的办法因为这些操作都是全局的所以hadoop不得不用一个reduce去完成。同样的在设置reduce个数的时候也需要考虑这两个原则使大数据量利用合适的reduce数使单个reduce任务处理合适的数据量Reduce阶段优化调整方式set mapred.reduce.tasks?set hive.exec.reducers.bytes.per.reducer ?一般根据输入文件的总大小,用它的estimation函数来自动计算reduce的个数reduce个数 InputFileSize / bytes per reducer7.JVM重用用于避免小文件的场景或者task特别多的场景这类场景大多数执行时间都很短因为hive调起mapreduce任务JVM的启动过程会造成很大的开销尤其是job有成千上万个task任务时JVM重用可以使得JVM实例在同一个job中重新使用N次set mapred.job.reuse.jvm.num.tasks10; --10为重用个数8.动态分区调整动态分区属性设置为true表示开启动态分区功能默认为falsehive.exec.dynamic.partitiontrue;动态分区属性设置为nonstrict,表示允许所有分区都是动态的默认为strict 设置为strict表示必须保证至少有一个分区是静态的hive.exec.dynamic.partition.modestrict;动态分区属性每个mapper或reducer可以创建的最大动态分区个数hive.exec.max.dynamic.partitions.pernode100;动态分区属性一个动态分区创建语句可以创建的最大动态分区个数hive.exec.max.dynamic.partitions1000;动态分区属性全局可以创建的最大文件个数hive.exec.max.created.files100000;控制DataNode一次可以打开的文件个数 这个参数必须设置在DataNode的$HADOOP_HOME/conf/hdfs-site.xml文件中property namedfs.datanode.max.xcievers/name value8192/value /property9.推测执行目的是通过加快获取单个task的结果以及进行侦测将执行慢的TaskTracker加入到黑名单的方式来提高整体的任务执行效率1修改 $HADOOP_HOME/conf/mapred-site.xml文件property namemapred.map.tasks.speculative.execution /name valuetrue/value /property property namemapred.reduce.tasks.speculative.execution /name valuetrue/value /property2修改hive配置set hive.mapred.reduce.tasks.speculative.executiontrue;10.数据倾斜表现任务进度长时间维持在99%或100%查看任务监控页面发现只有少量1个或几个reduce子任务未完成。因为其处理的数据量和其他reduce差异过大。单一reduce的记录数与平均记录数差异过大通常可能达到3倍甚至更多。最长时长远大于平均时长。原因1)、key分布不均匀2)、业务数据本身的特性3)、建表时考虑不周4)、某些SQL语句本身就有数据倾斜解决方案参数调节hive.map.aggrtrue11. 其他参数调优开启CLI提示符前打印出当前所在的数据库名set hive.cli.print.current.dbtrue;让CLI打印出字段名称hive.cli.print.headertrue;设置任务名称方便查找监控SET mapred.job.nameP_DWA_D_IA_S_USER_PROD;决定是否可以在 Map 端进行聚合操作set hive.map.aggrtrue;有数据倾斜的时候进行负载均衡set hive.groupby.skewindatatrue;对于简单的不需要聚合的类似SELECT col from table LIMIT n语句不需要起MapReduce job直接通过Fetch task获取数据set hive.fetch.task.conversionmore;12、小文件问题小文件是如何产生的1.动态分区插入数据产生大量的小文件从而导致map数量剧增。2.reduce数量越多小文件也越多(reduce的个数和输出文件是对应的)。3.数据源本身就包含大量的小文件。小文件问题的影响1.从Hive的角度看小文件会开很多map一个map开一个JVM去执行所以这些任务的初始化启动执行会浪费大量的资源严重影响性能。2.在HDFS中每个小文件对象约占150byte如果小文件过多会占用大量内存。这样NameNode内存容量严重制约了集群的扩展。小文件问题的解决方案从小文件产生的途经就可以从源头上控制小文件数量方法如下1.使用Sequencefile作为表存储格式不要用textfile在一定程度上可以减少小文件2.减少reduce的数量(可以使用参数进行控制)3.少用动态分区用时记得按distribute by分区对于已有的小文件我们可以通过以下几种方案解决1.使用hadoop archive命令把小文件进行归档2.重建表建表时减少reduce数量3.通过参数进行调节设置map/reduce端的相关参数如下设置map输入合并小文件的相关参数//每个Map最大输入大小(这个值决定了合并后文件的数量) set mapred.max.split.size256000000; //一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并) set mapred.min.split.size.per.node100000000; //一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并) set mapred.min.split.size.per.rack100000000; //执行Map前进行小文件合并 set hive.input.formatorg.apache.hadoop.hive.ql.io.CombineHiveInputFormat;设置map输出和reduce输出进行合并的相关参数//设置map端输出进行合并默认为true set hive.merge.mapfiles true //设置reduce端输出进行合并默认为false set hive.merge.mapredfiles true //设置合并文件的大小 set hive.merge.size.per.task 256*1000*1000 //当输出文件的平均大小小于该值时启动一个独立的MapReduce任务进行文件merge。 set hive.merge.smallfiles.avgsize16000000设置如下参数取消一些限制(HIVE 0.7后没有此限制)hive.merge.mapfilesfalse默认值true 描述是否合并Map的输出文件也就是把小文件合并成一个maphive.merge.mapredfilesfalse默认值false 描述是否合并Reduce的输出文件也就是在Map输出阶段做一次reduce操作再输出.set hive.input.formatorg.apache.hadoop.hive.ql.io.CombineHiveInputFormat;这个参数表示执行前进行小文件合并前面三个参数确定合并文件块的大小大于文件块大小128m的按照128m来分隔小于128m,大于100m的按照100m来分隔把那些小于100m的包括小文件和分隔大文件剩下的进行合并,最终生成了74个块。