Hive优化核心思想

把 Hive SQL 当做 MapReduce 程序去优化。

注:以下 SQL 不会转为 MapReduce 来执行:

  • select 仅查询本表字段
  • where 仅对本表字段做条件过滤

几种常用的优化策略

1、Explain 显示执行计划

在 sql 前添加关键字 explain,不会产生 MapReduce 任务,但会预先分析,程序大概需要执行的步骤。

例如:对表 person 进行统计

explain select count(*) from person;

从表中我们可以看出,执行这个语句程序大概要运行的步骤。

2、Hive 运行方式

Hive 默认的运行方式为集群模式,当使用集群模式的时候程序会把任务提交到服务器去运行。

举例:对表 cell_monitor 进行统计查询操作

select count(*) from cell_monitor;

从图中可以看出,MR任务被提交到服务器运行,时间为101秒,少量数据就提交到服务器,会严重消耗工作时间和增加服务器压力。

  • 本地模式

    开启本地模式

    set hive.exec.mode.local.auto=true;	#默认为false

    再次进行查询

    可以发现,运行时间大大缩短,同时节省资源,减轻服务器的压力。

  • 集群模式

    默认为 false

  • 本地加载文件的最大值

    hive.exec.mode.local.auto.inputbytes.max  #默认值为128M(134217728

    注意:若加载文件的最大值大于该配置,仍会以集群方式来运行!

3、严格模式

  • 通过设置以下参数开启严格模式[防止误操作]

    set hive.mapred.mode=strict;
    (默认为:nonstrict非严格模式)
  • 查询限制:

    1、对分区表查询时,必须添加 where 对于分区字段的条件过滤;
    2、order by 语句必须包含 limit 输出限制;
    3、限制执行笛卡尔积的查询

    如不满足,则会报错!

4、Hive 排序

  • Order By - 对于查询结果做全排序,只允许有一个 reduce 处理

    (当数据量较大时,应慎用。严格模式下,必须结合 limit 来使用,限制查询的数量)

  • Sort By - 对于单个 reduce 的数据进行排序(分布式处理)

  • Distribute By - 分区排序,经常和 Sort By 结合使用(对多个区进行排序)

  • Cluster By - 相当于 Sort By + Distribute By

    (Cluster By 不能通过 asc、desc 的方式指定排序规则;可通过 distribute by column sort by column asc|desc 的方式)

5、Hive Join

​ Join 计算时,将小表(驱动表,数据量较少的表)放在 join 的左边。

​ Map Join:在 Map 端完成 Join

  • 两种实现方式:

    (1)SQL 方式,在 SQL 语句中添加 MapJoin 标记(mapjoin hint)

    • 语法:
    SELECT  /*+ MAPJOIN(smallTable) */  smallTable.key,  bigTable.value 
    FROM smallTable JOIN bigTable ON smallTable.key = bigTable.key;

    (2)开启自动的 MapJoin

    通过修改以下配置启用自动的 mapjoin:

    set hive.auto.convert.join = true;
    (该参数为true时,Hive自动对左边的表统计量,如果是小表就加入内存,即对小表使用Map join

    其他相关配置参数:

    hive.mapjoin.smalltable.filesize;  
    (大表小表判断的阈值25MB左右,如果表的大小小于该值则会被加载到内存中运行)

    hive.ignore.mapjoin.hint;
    (默认值:true;是否忽略mapjoin hint 即map join标记)

    hive.auto.convert.join.noconditionaltask;
    (默认值:true;将普通的join转化为普通的map join时,是否将多个map join转化为一个map join

    hive.auto.convert.join.noconditionaltask.size;
    (将多个map join转化为一个map join时,其表的最大值(默认10MB))

    注意:如果两个表都是小表,尽量把真正较小的表放到左边,提高性能。

6、Map-Side聚合

​ 如 count() 等聚合函数

  • 通过设置以下参数开启在Map端的聚合:

    set hive.map.aggr=true;
  • 相关配置参数:

    hive.groupby.mapaggr.checkinterval;
    map端group by执行聚合时处理的多少行数据(默认:100000

    hive.map.aggr.hash.min.reduction:
    进行聚合的最小比例(预先对100000条数据做聚合,若 聚合的数据量/100000 的值小于该配置0.5,则不会聚合)

    hive.map.aggr.hash.percentmemory:
    map端聚合使用的内存的最大值(默认0.5

    hive.map.aggr.hash.force.flush.memory.threshold:
    map端做聚合操作是hash表的最大可用内容,大于该值则会触发flush(默认0.9

    hive.groupby.skewindata
    是否对Group By产生的数据倾斜做优化,默认为false

6、控制Hive中Map以及Reduce的数量

  • Map数量相关的参数

    mapred.max.split.size
    一个split的最大值,即每个map处理文件的最大值(默认256MB)

    mapred.min.split.size.per.node
    一个节点上split的最小值(默认1个)

    mapred.min.split.size.per.rack
    一个机架上split的最小值(默认1个)
  • Reduce数量相关的参数

    mapred.reduce.tasks
    强制指定reduce任务的数量(默认-1

    hive.exec.reducers.bytes.per.reducer
    每个reduce任务处理的数据量(默认256MB)

    hive.exec.reducers.max
    每个任务最大的reduce数(默认1009个)
    [ Map数量 >= Reduce数量 ]

7、Hive - JVM重用

用来设置粗细粒度。

  • 适用场景:

    (1)小文件个数过多

    (2)task 个数过多

  • 通过下列参数来设置

    set mapred.job.reuse.jvm.num.tasks=n;
    (n为 task 插槽个数)

    **插槽个数:**是 JVM 中的一个计量单位。举个例子:我们常用的 window 系统,有32位和64位的,我们会发现32位的操作系统上不能运行64位的软件程序,但是64位操作系统上却可以运行32位的软件,这是因为64位就等于两个32位,我们把一个32位比作一个插槽,那64位就是2个插槽了。

  • 缺点:

    设置开启之后,task插槽会一直占用资源,不论是否有task运行,直到所有的 task 即整个 job 全部执行完成时,才会释放所有的task插槽资源!