hive优化总结

Posted lrxvx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hive优化总结相关的知识,希望对你有一定的参考价值。

Hivehql注意事项

1、使用分区裁剪,列裁剪

在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在Where后面,那么就会先全表关联,之后再过滤,

SELECT a.id

FROM lxw1234_a a

left outer joint_lxw1234_partitioned b

ON (a.id = b.url);

WHEREb.day = 2015-05-10

 

使用SELECT a.id

FROM lxw1234_a a

left outer joint_lxw1234_partitioned b

ON (a.id =b.url AND b.day = 2015-05-10);

或者直接写成子查询:

SELECT a.id

FROM lxw1234_a a

left outer join(SELECT url FROM t_lxw1234_partitioned WHERE day = 2015-05-10) b

ON (a.id = b.url)

这两者的效果相同

列裁剪就不会导致全表扫描

 

2、少用COUNTDISTINCT

数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BYCOUNT的方式替换:

SELECT day,

COUNT(DISTINCT id)AS uv

FROM lxw1234

GROUP BY day

可以转换成:

SELECT day,

COUNT(id) AS uv

FROM (SELECTday,id FROM lxw1234 GROUP BY day,id) a

GROUP BY day;

虽然会多用一个Job来完成,但在数据量大的情况下,这个绝对是值得的。

还有就是distinct会多启动一个job,如果不是有意义的distinct的就不要使用

3、是否存在多对多的关联

只要遇到表关联,就必须得调研一下,是否存在多对多的关联,起码得保证有一个表或者结果集的关联键不重复。

如果某一个关联键的记录数非常多,那么分配到该Reduce Task中的数据量将非常大,导致整个Job很难完成,甚至根本跑不出来。

还有就是避免笛卡尔积,同理,如果某一个键的数据量非常大,也是很难完成Job的。

关联键请参考后面的join详解

4、合理使用MapJoin

参考后面的join详解

 

5、并行执行job

set hive.exec.parallel=true;   //打开任务并行执行

set hive.exec.parallel.thread.number=16; //同一个sql允许最大并行度,默认为8。

子查询并行也可以提供并行度,前提是资源足够

数据倾斜的处理

导致数据倾斜的操作GROUP BY, COUNTDISTINCT, join

 原因:key分布不均匀、业务数据本身特点

办法:

1、 使用COUNT DISTINCTGROUP BY造成的数据倾斜:

存在大量空值或NULL,或者某一个值的记录特别多,可以先把该值过滤掉,在最后单独处理:

多重COUNT DISTINCT通常使用UNION ALL +ROW_NUMBER() + SUM + GROUP BY来变通实现。

2、使用JOIN引起的数据倾斜关联键存在大量空值或者某一特殊值,

”NULL”空值单独处理,不参与关联,空值或特殊值加随机数作为关联键;

不同数据类型的字段关联转换为同一数据类型之后再做关联

3、控制Map数和Reduce

a、控制hive任务中的map

不是map越多越好也不是越少越好,小文件太多导致map太多,从而map的启动和初始化时间远远大于逻辑处理时间,就会造成资源的浪费

也不是map的处理的文件越接近128M越好,如果map处理的业务逻辑过于复杂,就会比较耗时,

所以针对小文件个数比较多就要合并小文件,减少map个数

map执行前合并小文件,减少map数方法如下:
set mapred.max.split.size=100000000;
set mapred.min.split.size.per.node=100000000;
set mapred.min.split.size.per.rack=100000000;
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
再执行上面的语句,用了74个map任务,map消耗的计算资源:SLOTS_MILLIS_MAPS= 333,500
对于这个简单SQL任务,执行时间上可能差不多,但节省了一半的计算资源。
大概解释一下,100000000表示100M, sethive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;这个参数表示执行前进行小文件合并,
前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),
进行合并,最终生成了74个块。

遇到文件比较大且处理逻辑复杂时,适当增加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.tasks=10;
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任务处理合适的数据量;

b、控制hive任务的reduce

hive.exec.reducers.bytes.per.reducer(每个reduce任务处理的数据量,默认为1000^3=1G)
hive.exec.reducers.max(每个任务最大的reduce数,默认为999)
计算reducer数的公式很简单N=min(参数2,总输入数据量/参数1)

调整reduce个数的方法

1、调整hive.exec.reducers.bytes.per.reducer参数的值;
set hive.exec.reducers.bytes.per.reducer=500000000; (500M)

2、set mapred.reduce.tasks = 15;

reduce个数并不是越多越好

以下情况会出现不管怎么都只会有一个reduce的情况

1、没有group by的汇总,比如把select pt,count(1) from popt_tbaccountcopy_mes where pt =‘2012-07-04′ group by pt; 写成 select count(1) frompopt_tbaccountcopy_mes where pt = ‘2012-07-04′;

2、用了Order by会进行全表的统计

3、有笛卡尔积

 

详解hivejoin

Hive中的Join可分为Common Join(Reduce阶段完成join)和Map Join(Map阶段完成join)。本文简单介绍一下两种join的原理和机制

Hive中Join的关联键必须在ON ()中指定,不能在Where中指定,否则就会先做笛卡尔积,再过滤。

1、Hive Common Join

如果不指定MapJoin或者不符合MapJoin的条件,那么Hive解析器会将Join操作转换成Common Join,即:在Reduce阶段完成join.
整个过程包含Map、Shuffle、Reduce阶段。

  • Map阶段

读取源表的数据,Map输出时候以Join on条件中的列为key,如果Join有多个关联键,则以这些关联键的组合作为key;
Map输出的value为join之后所关心的(select或者where中需要用到的)列;同时在value中还会包含表的Tag信息,用于标明此value对应哪个表;
按照key进行排序

  • Shuffle阶段

根据key的值进行hash,并将key/value按照hash值推送至不同的reduce中,这样确保两个表中相同的key位于同一个reduce中

  • Reduce阶段
    根据key的值完成join操作,期间通过Tag来识别不同表中的数据。
  1. 以下面的HQL为例,图解其过程:
  2. SELECT
  3. a.id,a.dept,b.age
  4. FROM a join b
  5. ON (a.id = b.id);

 技术图片

 

2、Hive Map Join

MapJoin通常用于一个很小的表和一个大表进行join的场景,具体小表有多小,由参数hive.mapjoin.smalltable.filesize来决定,该参数表示小表的总大小,默认值为25000000字节,即25M。

Hive0.7之前,需要使用hint提示 /*+ mapjoin(table) */才会执行MapJoin,否则执行Common Join,但在0.7版本之后,默认自动会转换Map Join,由参数hive.auto.convert.join来控制,默认为true.

仍然以9.1中的HQL来说吧,假设a表为一张大表,b为小表,并且hive.auto.convert.join=true,那么Hive在执行时候会自动转化为MapJoin。

  • 如图中的流程,首先是Task A,它是一个Local Task(在客户端本地执行的Task),负责扫描小表b的数据,将其转换成一个HashTable的数据结构,并写入本地的文件中,之后将该文件加载到DistributeCache中
  • 接下来是Task B,该任务是一个没有Reduce的MR,启动MapTasks扫描大表a,在Map阶段,根据a的每一条记录去和DistributeCache中b表对应的HashTable关联,并直接输出结果。
  • 由于MapJoin没有Reduce,所以由Map直接输出结果文件,有多少个Map Task,就有多少个结果文件。

mapjoin比common join多了一步,首先启动了一个本地的Map Reduce作业,读d表,

然后启动了一个非本地的Map Reduce作业,是一个真实的Map操作,读e表,

然后并没有启动真实的Reduce操作,而直接在Map端进行了join操作,最后展示数据。

使用优化器将commmon join 优化成mapjoin,省掉了Reduce操作,效率更高。

 

 技术图片

 

 count() count(if) count(distinct if) sum(if)的用法和区别

博客地址https://www.cnblogs.com/zzhangyuhang/p/9799303.html

如:

--初步统计域名数据到临时表中

INSERT OVERWRITE TABLE tmp.tmp_table_arch_50x_report_access_$date

SELECT host,count(1) AS req_cnt,

sum(if(status in (500,502,503,504),1,0)) as error_cnt

from ods.ods_table_log_vps_ngx_access

where dt="$date"

GROUP BY host

采用这种方式不用group by两个字段,并且可以统计出来

 

 

以上是关于hive优化总结的主要内容,如果未能解决你的问题,请参考以下文章

Hive优化总结

hive&hue优化

hive优化总结

hive优化方法

hive优化总结

hive优化方式总结