9.Hive系列之企业级调优

1. 执行计划(Explain)
explain select * from emp
# 没有生成 MR 任务的
Explain
STAGE DEPENDENCIES:
 Stage-0 is a root stage
STAGE PLANS:
 Stage: Stage-0
 Fetch Operator
...
# 有生成 MR 任务的
Explain
STAGE DEPENDENCIES:
 Stage-1 is a root stage
 Stage-0 depends on stages: Stage-1
STAGE PLANS:
 Stage: Stage-1
 Map Reduce
 Map Operator Tree:
 Reduce Operator Tree:
...
2. Fetch 抓取

Fetch 抓取是指,Hive 中对某些情况的查询可以不必使用 MapReduce 计算。例如:SELECT* FROM employees;在这种情况下,Hive 可以简单地读取 employee 对应的存储目录下的文件,然后输出查询结果到控制台

在 hive-default.xml.template 文件中 hive.fetch.task.conversion 默认是more,老版本 hive默认是 minimal,该属性修改为 more 以后,在全局查找、字段查找、limit 查找等都不走mapreduce。

  • 把 hive.fetch.task.conversion 设置成 none,然后执行查询语句,都会执行mapreduce程序
hive (default)> set hive.fetch.task.conversion=none;
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;
  • 把 hive.fetch.task.conversion 设置成 more,然后执行查询语句,如下查询方式都不会执行 mapreduce 程序
hive (default)> set hive.fetch.task.conversion=more;
hive (default)> select * from emp;
hive (default)> select ename from emp;
hive (default)> select ename from emp limit 3;
3. 本地模式

大多数的 Hadoop Job 是需要 Hadoop 提供的完整的可扩展性来处理大数据集的。不过,有时 Hive 的输入数据量是非常小的。在这种情况下,为查询触发执行任务消耗的时间可能会比实际 job 的执行时间要多的多。对于大多数这种情况,Hive 可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短

用户可以通过设置 hive.exec.mode.local.auto 的值为 true,来让 Hive 在适当的时候自动启动这个优化,默认为false

# 开启本地 mr
set hive.exec.mode.local.auto=true; 
# 设置 local mr 的最大输入数据量,当输入数据量小于这个值时采用 local mr 的方式,默认为 134217728,即 128M
set hive.exec.mode.local.auto.inputbytes.max=50000000;
# 设置 local mr 的最大输入文件个数,当输入文件个数小于这个值时采用 local mr 的方式,默认为 4
set hive.exec.mode.local.auto.input.files.max=10;
4. 表的优化
4.1 小表大表 Join(MapJOIN)

将 key 相对分散,并且数据量小的表放在 join 的左边,可以使用 map join 让小的维度表先进内存。在 map 端完成 join。
某谷实际测试发现:新版的 hive 已经对小表 JOIN 大表和大表 JOIN 小表进行了优化。小表放在左边和右边已经没有区别。

4.2 大表 Join 大表
  1. 空 KEY 过滤

有时 join 超时是因为某些 key 对应的数据太多,而相同 key 对应的数据都会发送到相同的 reducer 上,从而导致内存不够。此时我们应该仔细分析这些异常的 key,很多情况下,这些 key 对应的数据是异常数据,我们需要在 SQL 语句中进行过滤。例如 key 对应的字段为空,操作如下

insert overwrite table jointable select n.* from (select * from nullidtable where id is not null) n left join bigtable o on n.id = o.id;
  1. 空 key 转换

有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的 reducer 上

insert overwrite table jointable select n.* from nullidtable n full join bigtable o on nvl(n.id,rand()) = o.id;
  1. SMB(Sort Merge Bucket join)

对于两个大表join可优化为两个分桶表进行join,桶的个数不要超过可用 CPU 的核数

set hive.optimize.bucketmapjoin = true;
set hive.optimize.bucketmapjoin.sortedmerge = true;
set hive.input.format=org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
4.3 Group By

默认情况下,Map 阶段同一 Key 数据分发给一个 reduce,当一个 key 数据过大时就倾斜了。并不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在 Map 端进行部分聚合,最后在 Reduce 端得出最终结果

  1. 开启 Map 端聚合参数设置

是否在 Map 端进行聚合,默认为 True

set hive.map.aggr = true

在 Map 端进行聚合操作的条目数目

set hive.groupby.mapaggr.checkinterval = 100000

有数据倾斜的时候进行负载均衡(默认是 false)

set hive.groupby.skewindata = true
4.4 Count(Distinct) 去重统计

数据量小的时候无所谓,数据量大的情况下,由于 COUNT DISTINCT 操作需要用一个Reduce Task 来完成,这一个 Reduce 需要处理的数据量太大,就会导致整个 Job 很难完成,一般 COUNT DISTINCT 使用先 GROUP BY 再 COUNT 的方式替换,但是需要注意 group by 造成的数据倾斜问题

select count(id) from (select id from bigtable group by id) a;
4.5 笛卡尔积

尽量避免笛卡尔积,join 的时候不加 on 条件,或者无效的 on 条件,Hive 只能使用 1 个reducer 来完成笛卡尔积

4.6 行列过滤

列处理:在 SELECT 中,只拿需要的列,如果有分区,尽量使用分区过滤,少用 SELECT *
行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在 Where 后面,那么就会先全表关联,之后再过滤,请先通过子查询过滤

测试先关联两张表,再用 where 条件过滤

hive (default)> select o.id from bigtable b join bigtable o on o.id = b.id where o.id <= 10;
Time taken: 34.406 seconds, Fetched: 100 row(s)

通过子查询后,再关联表

select b.id from bigtable b
join (select id from bigtable where id <= 10) o on b.id = o.id;
Time taken: 30.058 seconds, Fetched: 100 row(s)
4.7 分区
4.8 分桶

5 合理设置 Map 及 Reduce 数

  • 复杂文件增加 Map 数
  • CombineHiveInputFormat小文件进行合并
  • 处理大数据量利用合适的 reduce 数

6. 并行执行

默认情况下,Hive 一次只会执行一个阶段。不过,某个特定的 job 可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个 job 的执行时间缩短

# 打开任务并行执行
set hive.exec.parallel=true; 
# 同一个 sql 允许最大并行度,默认为8
set hive.exec.parallel.thread.number=16;

7. 严格模式

Hive 可以通过设置防止一些危险操作:

  1. 分区表不使用分区过滤 将 hive.strict.checks.no.partition.filter 设置为true时,对于分区表,除非 where 语句中含有分区字段过滤条件来限制范围,否则不允许执行
  2. 使用 order by 没有 limit 过滤 将 hive.strict.checks.orderby.no.limit 设置为true 时,对于使用了 order by 语句的查询,要求必须使用 limit 语句
  3. 笛卡尔积 将 hive.strict.checks.cartesian.product 设置为 true 时,会限制笛卡尔积的查询

猜你喜欢

转载自blog.csdn.net/SJshenjian/article/details/131873458