一,调优基础 :

1 ,连接暗示 :

  1. 需求 : 让 join 发生在 map 端
  2. sql :
select /*+ mapjoin(customers) */ a.*,b.* 
from customers a left outer join orders b 
on a.id=b.cid;

2 ,hive 执行计划

hql 在执行的时候,是转化成了什么样的 mr 去执行的。

3 ,查看执行计划 : explain

select count(1) from wc;
explain select count(1) from wc;

4 ,SQL 转化为 MapReduce 的过程

  1. Antlr 定义 SQL 的语法规则,完成 SQL 词法,语法解析,将 SQL 转化为抽象语法树 AST Tree
  2. 遍历 AST Tree,抽象出查询的基本组成单元 QueryBlock
  3. 遍历 QueryBlock,翻译为执行操作树OperatorTree
  4. 逻辑层优化器进行 OperatorTree 变换,合并不必要的 ReduceSinkOperator,减少 shuffle 数据量
  5. 遍历 OperatorTree,翻译为 MapReduce 任务
  6. 物理层优化器进行 MapReduce 任务的变换,生成最终的执行计划

二 ,调优 :

1 ,不用 select *

2 ,不要出现 笛卡尔积

join … on …

3 ,数据量大的情况下,减少 count(distinct)

原因 : count(distinct) 容易产生倾斜问题。

4 ,减少 map 数 :每个文件对应一个 map 任务

  1. 已知 : 194 个文件,其中很多是远远小于 128m 的小文件,总大小 9G 。
  2. Map 总共消耗的计算资源: SLOTS_MILLIS_MAPS = 623,020k ( )
  3. 调优 :
1.  1 ,小文件合并 :这个参数表示执行前进行小文件合并
 set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
 2 ,小文件合并参数 :
 // 文件块最大值
 set mapred.max.split.size=100000000; ( 100M )
 // 一个节点上 split 至少的大小 ( 文件块最小值 )
 set mapred.min.split.size.per.node=100000000;
 // 一个交换机下split的至少的大小
 set mapred.min.split.size.per.rack=100000000;
 3 ,底层代码 : 解释 set mapred.max.split.size
 minSize=max{minSplitSize,mapred.min.split.size} (minSplitSize大小默认为1B)
 maxSize=mapred.max.split.size(不在配置文件中指定时大小为Long.MAX_VALUE)
 splitSize=max{minSize,min{maxSize,blockSize}}
  1. 结果 :
    1 ,大于文件块大小 128m 的,按照 128m 来分隔。
    2 ,小于 128m ,大于 100m 的,按照 100m 来分隔。
    3 ,把那些小于 100m 的(包括小文件和分隔大文件剩下的),进行合并。
    4 ,最终生成了74个块。
  2. 消耗 :
    map 消耗的计算资源:SLOTS_MILLIS_MAPS= 333,500

5 ,增加 map 数 : 某些情况并不是任务数越少越好

  1. 在第四点中 :我们分析,为了节省资源,不能让很多小文件产生,增加我们的 mr 任务数。
  2. 但是 :如果有这么一个文件,他只有两列 ( id int,name string ),但是,他有几千万条记录,这种情况,很明显,不能让一个 map 去处理,就需要增加任务数。
  3. 做法 : 虽然只有一个 map ,但是我们可以设置多个 reduce 。
    set mapred.reduce.tasks=10;
    create table a_1 as
    select * from a
    distribute by rand(123);
  4. 结果 :
    先分文件再执行,distribute 就是分文件的意思

6 ,指定 reduce 个数 :例如 15 个

set mapred.reduce.tasks = 15;

7 ,不指定 reduce 个数 :

设定以下两个限制条件 :
hive.exec.reducers.bytes.per.reducer :每个 reduce 任务处理的数据量,默认为 1G 。
hive.exec.reducers.max :每个任务最大的 reduce 数,默认为 999

8 ,hive 严格模式 : 防止大资源消耗性查询

默认 :严格模式
严格模式 : 防止用户执行那些可能产生意想不到的不好的效果的查询。
可以禁止 3 种类型的查询。
设置严格模式 :
set hive.mapred.mode=strict;
禁止的三种类型 :
1 ,分区表不能扫描全表 : 查询时,必须加分区字段,也就是不能查询所有数据。
2 ,order by 必须与 limit 连用 :全表排序将会是一项巨大的工程,因此必须加以限制。
3 ,限制笛卡尔积的查询 :必须 join on 连用,不可以 join - where 连用。

9 ,hive 本地模式 ( 测试用,小任务用 )

  1. 原理 :对于小数据集,本地模式的执行时间会明显被缩短。
  2. 适用场景 : 必须满足以下条件
    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
  3. 设置本地模式 :
    set hive.exec.mode.local.auto=true;(默认为false)
    查看本地模式是否打开 :set hive.exec.mode.local.auto
  4. 测试 :select count(1) from emp; 不使用本地模式 : 22 秒

hive MR hive mr 推测执行_执行时间

  1. 使用本地模式 : 3 秒

hive MR hive mr 推测执行_SQL_02

10 ,hive 推测执行

  1. mr 的推测执行 :数据倾斜的时候,有的任务执行时间较长,apm 默认推测此任务出现问题,另启一个任务进行执行,以先执行完毕的结果为准,
  2. sql 不支持 :
    使用SQL语句时将其关闭
  3. 设置 : Hadoop的mapred-site.xml
<property>
    <name>mapreduce.map.speculative</name>
    <value>true</value>
    <description>
    	If true, then multiple instances of some map tasks 
    	may be executed in parallel.
    </description>
</property>
<property>
    <name>mapreduce.reduce.speculative</name>
    <value>true</value>
    <description>If true, then multiple instances of some reduce tasks 
    may be executed in parallel.
    </description>
</property>
  1. 设置 : hive 端
<property>
    <name>hive.mapred.reduce.tasks.speculative.execution</name>
    <value>true</value>
    <description>
    	Whether speculative execution for reducers 
		should be turned on.     
    </description>
</property>

11 ,JVM 重用

  1. 设置 ( 比如 10 个 ) : set mapred.job.reuse.jvm.num.tasks=10;
  2. 适用场景 :很多小文件的场景或者 task 特别多的场景,这类场景大多数执行时间都很短。
  3. 原理 :
    1 ,很多小文件的场景或者 task 特别多的场景,这类场景大多数执行时间都很短。
    2 ,hadoop 默认配置是使用派生 JVM 来执行 map 和 reduce 任务的。
    3 ,这时 jvm 的启动过程可能会造成相当大的开销,尤其是执行的 job 包含有成千上万个 task 任务的情况。

12 ,并行执行

  1. 原理 : 同步执行hive的多个阶段,hive在执行过程,将一个查询转化成一个或者多个阶段。某个特定的job可能包含众多的阶段,而这些阶段可能并非完全相互依赖的,也就是说可以并行执行的,这样可能使得整个job的执行时间缩短
  2. 设置 :set hive.exec.parallel=true;