1、Hive压缩
- 概述:Hive的压缩是MR的压缩,分为Map端结果文件压缩和Reduce端结果文件压缩
- 压缩性能比较
压缩算法 | 原始文件大小 | 压缩文件大小 | 压缩速度 | 解压速度 |
gzip | 8.3GB | 1.8GB | 17.5MB/s | 58MB/s |
bzip2 | 8.3GB | 1.1GB | 2.4MB/s | 9.5MB/s |
LZO | 8.3GB | 2.9GB | 49.3MB/s | 74.6MB/s |
Snappy | 8.3GB | 3G | 250MB/S | 500 MB/s |
按照Hive对数据的分层,我们可以在对应层使用这样的压缩方式:
层级 | 压缩方式 | 原因 |
ODS层 | zlib、gz、bz2 | 省空间 |
DW层 | snappy | 速度快 |
DA层 | snappy | 速度快 |
- 相关参数设置
-- 开启Map端压缩
set hive.exec.compress.intermediate=true;
set mapreduce.map.output.compress=true;
set mapreduce.map.output.compress.codec= org.apache.hadoop.io.compress.SnappyCodec;
-- 开启hive最终输出数据压缩功能
set hive.exec.compress.output=true;
-- 开启mapreduce最终输出数据压缩
set mapreduce.output.fileoutputformat.compress=true;
-- 设置mapreduce最终数据输出压缩方式
set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodec;
-- 设置mapreduce最终数据输出压缩为块压缩
set mapreduce.output.fileoutputformat.compress.type=BLOCK;
2、Hive存储格式
- hive的存储格式分为行式存储和列式存储
- hive的默认存储方式是行式存储中的TextFile,除此之外,还有SequenceFile
- 列式存储也有两个:ORC和PARQUET
以下是行式存储和列式存储的示意图
当我们选择使用行式存储,查询所有字段的时候,查询效率最高,如:
SELECT * FROM TABLE_NAME [WHERE CONDITION]
但是,如果查询具体某几个字段时,查询效率就比较低,但对于列式存储来说,效率却能得到很大提升。一般项目中,我们使用的是列式存储,一般使用的是ORC存储
- 建表时指定存储格式
这过程中,使用ORC列式存储方式的数据会进行压缩,使数据的摆放方式更加合理。
orc内部默认采用的压缩算法是zlib
-- 建表(默认)
create table test_text (
id int,
name string
)
row format delimited fields terminated by '\t';
-- 加载数据到test_text
load data inpath '/hive/text.log' into test_text;
-- 建表(orc)
create table test_orc (
id int,
name string
)
row format delimited fields terminated by '\t'
stored as orc;
-- 加载数据,查询并插入(执行MapReduce)
insert into test_orc select * from test_text;
- 建表时指定存储格式的压缩算法
上面说到ORC的默认压缩算法为zlib,我们也可以通过设置去指定其压缩算法
create table test_orc_snappy(
id int,
name string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties ("orc.compress"="SNAPPY");
所以,结合压缩算法,我们对hive的分层中,可以通过存储格式和压缩方式进行结合,达到我们对每个分层的优化效果
层级 | 压缩方式 | 存储格式 | 原因 |
ODS层 | zlib、gz、bz2 | ORC | 省空间 |
DW层 | snappy | ORC | 速度快 |
DA层 | snappy | ORC | 速度快 |
3、Hive优化
- 本地调优
在本地模式时,在数据量小的情况下,可以通过设置以下方法,达到优化查询的目的
set hive.stats.column.autogather=false;
set hive.exec.mode.local.auto=true;
3.1、空key问题
- 谓词下推
在做join操作的时候,如果本身数据存在null值,那么联表时会造成很多非必要的链表操作,此时我们可以在联表前做空key的过滤操作
select * from A a where 过滤条件
select * from B a where 过滤条件
select * from (select * from A a where 过滤条件) a left join (select * from B b 过滤条件) b on 连接条件
- 加盐操作
针对null值的待连接的表数据,有时候它本身的存在是有意义的,这时候不应该被过滤掉,可以考虑加盐操作,加盐还有个好处,就是防止数据在reduce端造成倾斜的情况
SELECT a.*
FROM Table1 a
LEFT JOIN Table2 b ON CASE WHEN a.id IS NULL THEN concat('table1', rand()) ELSE a.id END = b.id;
3.2、去重
- distinct: 注意,在Hive中distinct必须只有一个reduce才能完成整体的去重,效率极低,千万不要用
- group by
- row_number() over():生产环境使用
select distinct * from 表;
select sid,sname,sbirth,ssex from student2 group by sid,sname,sbirth,ssex;
with t as (
select
*,
row_number() over (partition by sid ) rk
from student2
)
select * from t where rk = 1;