Hadoop_15_hive调优

hive数据存储与压缩

数据的存储格式:
两大类:行式存储 列式存储

行式存储两种:textFile sequenceFile
列式存储两种:parquet orc
一般原始数据,别人给过来的,都是textfile这种形式的
经过分析之后通过insert overwrite select 将我们分析出来的结果插入到另外一张临时表里面就可以使用parquet 或者orc这些列式存储格式

在实际的项目开发当中,hive表的数据存储格式一般选择:orc或parquet。压缩方式一般选择snappy。

ORC存储方式默认ZLIB压缩方式
1)创建一个非压缩的的ORC存储方式

//建表
create table log_orc_none(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties ("orc.compress"="NONE");

//插入数据
insert into table log_orc_none select * from log_text ;

//查看插入后数据
dfs -du -h /user/hive/warehouse/myhive.db/log_orc_none;

2)创建一个SNAPPY压缩的ORC存储方式

//建表
create table log_orc_snappy(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties ("orc.compress"="SNAPPY");
//插入数据
insert into table log_orc_snappy select * from log_text ;
//查看插入后数据
dfs -du -h /user/hive/warehouse/myhive.db/log_orc_snappy ;

调优

Fetch抓取

能不走mr的就尽量不走mr。

hive.fetch.task.conversion 可配置取值 none, minimal, more
默认值是 more
如果设置成none,所有的都要走mr select * 也要走

下面这些都不会执行mapreduce程序。
hive (default)> set hive.fetch.task.conversion=more;
hive (default)> select * from score;
hive (default)> select s_score from score;
hive (default)> select s_score from score limit 3;

hive本地模式

可以限制我们输入数据的个数小于多少个。

当有大量小文件,造成分配资源时间远超过数据处理时间时,可以采用hive本地模式。
限制我们输入的数据量小于一定值时,启用本地模式运行,所有数据都在一个maptask,一个reducetask里面处理。

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

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

//开启本地模式,并执行查询语句
hive (default)> set hive.exec.mode.local.auto=true; 
hive (default)> select * from score cluster by s_id;
18 rows selected (1.568 seconds)

//关闭本地模式,并执行查询语句
hive (default)> set hive.exec.mode.local.auto=false; 
hive (default)> select * from score cluster by s_id;

Hadoop中可通过mapred-site.xml,配置小任务模式

<name>mapreduce.job.ubertask.enable</name>
<value>true</value>

表的优化

Join

早期的hive版本
小表join大表 会将小表的数据一次性进入到内存当中去,与右边大表进行匹配
现在的版本已经不存在这一条优化了,hive会有一个优化器,经过自动选择,可以自动的找出哪个表是小表,将小表的数据一次性放到内存

select count(distinct s_id) from score;

select count(1) from (
select count(s_id) from score group by s_id
) temp;

由于mapTask远多于Reduce,一个reduce端要处理很多数据,所以先在map端对数据进行一次聚合,然后发送到reduce数据会变少,然后再count的时候就会比较快。

在这里插入图片描述多个表关联时,最好分拆成小段,避免大sql(无法控制中间Job,都在写一起不知道具体哪一步慢)

大表Join大表,尽量的减少输入的数据量

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

不过滤:
INSERT OVERWRITE TABLE jointable
SELECT a.* FROM nullidtable a JOIN ori b ON a.id = b.id;

过滤:
INSERT OVERWRITE TABLE jointable
SELECT a.* FROM (SELECT * FROM nullidtable WHERE id IS NOT NULL ) a JOIN ori b ON a.id = b.id;

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

不随机分布:

set hive.exec.reducers.bytes.per.reducer=32123456;
set mapreduce.job.reduces=7;
INSERT OVERWRITE TABLE jointable
SELECT a.*
FROM nullidtable a
LEFT JOIN ori b ON CASE WHEN a.id IS NULL THEN 'hive' ELSE a.id END = b.id;

随机分布:

set hive.exec.reducers.bytes.per.reducer=32123456;
set mapreduce.job.reduces=7;
INSERT OVERWRITE TABLE jointable
SELECT a.*
FROM nullidtable a
LEFT JOIN ori b ON CASE WHEN a.id IS NULL THEN concat('hive', rand()) ELSE a.id END = b.id;

MapJoin

新版本当中小表join大表,以及大表join小表没有区别了

开启map端的join功能
set hive.auto.convert.join = true; 默认为true

Group By

有很多时候数据都可以在map端先进行一次聚合 类似于规约
先进行分组,再聚合,可以用两个mapreduce来完成。

Count(distinct)

直接去重,只能有一个reducetask,数据处理会比较慢
SELECT count(DISTINCT id) FROM bigtable;

select count(1) from (
SELECT count(id) FROM (SELECT id FROM bigtable GROUP BY id) a
) tempTable
虽然多一个mapreduce,但是速度会变快。

笛卡尔积

任何时候都要避免笛卡尔积
join的时候一定要避免无效的on条件

使用分区剪裁、列剪裁

只取我们用到的分区,只取我们用到的字段
不要写select * 对于分区表,一定要带上分区条件
减少数据的输入量

SELECT a.id
FROM bigtable a
LEFT JOIN ori b ON a.id = b.id
WHERE b.id <= 10;

//先过滤,再join

SELECT a.id
FROM ori a
LEFT JOIN bigtable b ON (a.id <= 10 AND a.id = b.id);

SELECT a.id
FROM bigtable a
RIGHT JOIN (
SELECT id
FROM ori
WHERE id <= 10
) b ON a.id = b.id;

动态分区调整

适用于分区表数据。以第一个表的分区规则,来对应第二个表的分区规则,将第一个表的所有分区,全部拷贝到第二个表中来,第二个表在加载数据的时候,不需要指定分区了,直接用第一个表的分区即可

  1. 开启动态分区功能(默认true,开启)
    set hive.exec.dynamic.partition=true;
  2. 设置为非严格模式(动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。)
    set hive.exec.dynamic.partition.mode=nonstrict;
  3. 在所有执行MR的节点上,最大一共可以创建多少个动态分区。
    set hive.exec.max.dynamic.partitions=1000;
  4. 在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值100,则会报错。
    set hive.exec.max.dynamic.partitions.pernode=100
  5. 整个MR Job中,最大可以创建多少个HDFS文件。
    在linux系统当中,每个linux用户最多可以开启1024个进程,每一个进程最多可以打开2048个文件,即持有2048个文件句柄,下面这个值越大,就可以打开文件句柄越大
    set hive.exec.max.created.files=100000;
  6. 当有空分区生成时,是否抛出异常。一般不需要设置。
    set hive.error.on.empty.partition=false;

不用动态分区的时候插入数据,需要手动的指定分区值
insert overwrite table ori_partitioned_target PARTITION (p_time=‘20130812’)
select id, time, uid, keyword, url_rank, click_num, click_url from ori_partitioned;

使用动态分区,不用手动指定分区值,但是select字段的时候,最后面的字段,一定要是分区字段
分区字段的值不能是中文
INSERT overwrite TABLE ori_partitioned_target PARTITION (p_time)
SELECT id, time, uid, keyword, url_rank, click_num, click_url, p_time
FROM ori_partitioned;

分桶

将大文件,按照一定的规则,划分成多个小文件

数据倾斜

map个数:block块大小有关,一个block块对应一个maptask
reduce个数: job.setNumReduceTasks(10) 手动指定

map个数

map和reduce的个数并不是越多越好。
如果有一个block块,里面有几千万条记录,map处理比较复杂。
如何减少map个数?

  • 调整block块的大小
  • 合并小文件
    set mapred.max.split.size=112345600;
    set mapred.min.split.size.per.node=112345600;
    set mapred.min.split.size.per.rack=112345600;
    set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
    这个参数表示执行前进行小文件合并,前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),进行合并。大于128M的文件,按照128M来进行切分,100到128按照100进行切分。切分剩下的小文件,进行合并。

如何增加map个数?
可以使用distributed by来先将文件计算一遍,打散成很多的小文件

set mapreduce.job.reduces =10;
create table a_1 as
select * from a
distribute by rand(123);
将我们的表数据,均匀的打散成十个小文件,这样就最少会有10个maptask

reduce个数

  1. 调整reduce个数方法一
    1)每个Reduce处理的数据量默认是256MB
    hive.exec.reducers.bytes.per.reducer=256123456
    2)每个任务最大的reduce数,默认为1009
    hive.exec.reducers.max=1009
    3)计算reducer数的公式
    N=min(参数2,总输入数据量/参数1)

  2. 调整reduce个数方法二
    在hadoop的mapred-default.xml文件中修改
    设置每个job的Reduce个数
    set mapreduce.job.reduces = 15;

jvm重用

container执行完了maptask或者reducetask之后,不要释放资源
继续给下一个maptask或者reduetask进行执行。

在hive当中设置jvm重用
 set  mapred.job.reuse.jvm.num.tasks=10;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值