Hive 可以直接将 SQL 语句 转换为 MapReduce 任务,无需关注底层的细节。但是要调优 Hive,就必须知道 Hive 背后的原理才可以进行后序的调优工作。今天开始调优的学习。

1.EXPLAIN

了解 Hive 的查询语句如何转为 MapReduce 程序才能知道如何调优。EXPLAIN 功能可以帮助我们学习 Hive 是如何将查询转换为 MapReduce 任务的。用法是加在查询语句的前面,例如:

EXPLAIN SELECT SUM(number) FROM num_tb;

2.EXPALIN EXTENDED

EXPALIN EXTENDED 可以产生更多的输出信息。

3.LIMIT

LIMIT 通常还是需要执行整个查询语句,得到结果后才返回限制的部分结果。Hive 有一个属性可以调优,开启后使用 LIMIT 时对数据源进行抽样:

SET hive.limit.optimize.enable=true;

# 开启后有两个参数可以设置
hive.limit.row.max.size
hive.limit.optimize.limit.file

缺点:由于是抽样,可能有用的数据永远不会被处理到。如果偏差可以接收则可以使用。

4.JOIN 优化

主要是 map-side JOIN。小表可以完全载入内存,大表放右边。

5.本地模式

数据量非常小时,触发执行任务的时间比 job 的执行时间还要长,这时可以用本地模式在单台机器上执行。

# 临时启用本地模式
SET oldjobtracker=${hiveconf:mapred.job.tracker};	-- 保存之前的配置
SET mapred.job.tracker=local;	-- 设置本地模式
SET mapred.tmp.dir=/home/edward/tmp;

SELECT * FROM tb WHERE ... ;

SET mapred.job.tracker=${oldjobtracker};	-- 还原之前的配置

或者通过设置 hive.exec.mode.local.auto=true 来让 Hive 在适当的时候自动执行这个优化。

6.并行执行

Hive 将查询转化成多个阶段,默认一次只执行一个阶段。如果有的阶段可以并行执行那么可以缩短执行时间。可以设置 hive.exec.parallel=true 来开启并发执行。

7.严格模式

设置 hive.mapred.mode=strict 可以禁止 3 种类型的查询:

  • 对于分区表,WHERE 语句必须包含分区字段;
  • 使用了 ORDER BY 的查询必须使用 LIMIT 语句;
  • 限制笛卡尔积查询。

8.调整 mapper 和 reducer 个数

  • 个数太多:启动、调度、运行 job 过程中开销太大;
  • 个数太少:没有充分利用集群的并行性。

例如:

# 先用 dfs -count 命令计算输入量大小,假如是 3GB
# 如果设置每个 reducer 处理 750MB(默认是 1GB),那么执行这个任务就要 4 个 reducer
SET hive.exec.reducers.bytes.per.reducer=750000000;

设置 hive.exec.reducers.max 可以防止一个 job 消耗掉所有资源导致其他任务无法执行。

Hive 的默认 reducer 数量是 3,通过设置 mapred.reduce.tasks 属性的值可以确定使用较多还是较少的 reducer 来缩短执行时间。

9.JVM 重用

Hadoop 的默认配置是派生 JVM 来执行 map 和 reduce 任务。JVM 的启动可能造成很大的开销。JVM 重用可以设置一个 JVM 实例在同一个 job 中重新使用 N 次。

10.索引

索引可以加快 GROUP BY 的查询速度。前面的文章写过索引的建立方法。点击下方连接查看。

11.动态分区调整

动态分区 INSERT 语句可以通过简单的 SELECT 语句向分区表中创建很多新的分区。

# 动态分区
insert overwrite table employees
partition (country,state)
select ...,se.cnty,se.st
from staged_employees se;

# 动态 静态混合使用,静态分区键必须在动态分区键前面
insert overwrite table employees
partition (country='US',state)
select ...,se.cnty,se.st
from staged_employees se
where se.cnty='US';

通过设置动态分区为严格模式 hive.exec.dynamic.partition.mode=strict 可以保证至少有一个分区是静态的。通过 hive.exec.max.dynamic.partitions 设置最大动态分区个数。

12.推测执行

推测执行触发重复的任务,通过加快获取单个 task 的结果以及将执行慢的 TaskTracker 加入黑名单来提高整个任务的执行效率。

Hadoop 的推测执行功能由 mapred.map.tasks.speculative.executionmapred.reduce.tasks.speculative.execution 来控制。Hive 中通过 hive.mapred.reduce.tasks.speculative.execution 来控制。

13.单个 MapReduce 中执行多个 GROUP BY

通过 hive.multigroupby.singlemr=true 来启动。需要一组常用的 GROUP BY 键。

14.虚拟列

Hive 提供了一些虚拟列可以查询,便于查看哪个文件或哪行数据出现了问题。

SET hive.exec.rowoffset=true;	-- 开启

SELECT INPUT_FILE_NAME,BLOCK_OFFSET_INDISE_FILE,line
FROM hive_text WHERE line LIKE '%hive%' LIMIT 2;

SELECT INPUT_FILE_NAME,BLOCK_OFFSET_INDISE_FILE,ROW_OFFSET_INSIDE_BLOCK
FROM hive_text WHERE line LIKE '%hive%' LIMIT 2;