Hive的压缩存储和简单优化
一、Hive的压缩和存储
1,MapReduce支持的压缩编码
压缩格式 |
工具 |
算法 |
文件扩展名 |
是否可切分 |
对应的编码/解码器 |
DEFLATE |
无 |
DEFLATE |
.deflate |
否 |
org.apache.hadoop.io.compress.DefaultCodec |
Gzip |
gzip |
DEFLATE |
.gz |
否 |
org.apache.hadoop.io.compress.GzipCodec |
bzip2 |
bzip2 |
bzip2 |
.bz2 |
是 |
org.apache.hadoop.io.compress.BZip2Codec |
LZO |
lzop |
LZO |
.lzo |
是 |
com.hadoop.compression.lzo.LzopCodec |
Snappy |
无 |
Snappy |
.snappy |
否 |
org.apache.hadoop.io.compress.SnappyCodec |
2,文件压缩格式:
TEXTFILE和SEQUENCEFILE的存储格式都是基于行式存储的;
ORC和PARQUET是基于列式存储的。
a>TextFile格式:
默认格式,数据不做压缩,磁盘开销大,数据解析开销大。可结合Gzip、Bzip2使用,但使用Gzip这种方式,hive不会对数据进行切分,从而无法对数据进行并行操作。
b>Orc格式:
Hive 0.11版里引入的新的存储格式,数据按行分块 每块按照列存储 ,压缩快 快速列存取,效率比rcfile高,是rcfile的改良版本,相比RC能够更好的压缩,能够更快的查询,但还是不支持模式演进。
c>parquent格式:
Parquet文件是以二进制方式存储的,所以是不可以直接读取的,文件中包括该文件的数据和元数据,因此Parquet格式文件是自解析的。
在实际的项目开发当中,hive表的数据存储格式一般选择:orc或parquet。压缩方式一般选择snappy,lzo。
二、Hive的企业级调优:
1,Fetch抓取:
默认开启。Fetch抓取是指,Hive中对某些情况的查询可以不必使用MapReduce计算。(hive-default.xml.template文件中hive.fetch.task.conversion默认是more)例如:SELECT * FROM person;在这种情况下,Hive可以简单地读取person对应的存储目录下的文件,然后输出查询结果到控制台。
2,本地模式:
大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过,有时Hive的输入数据量是非常小的。在这种情况下,为查询触发执行任务消耗的时间可能会比实际job的执行时间要多的多。对于大多数这种情况,Hive可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。
set hive.exec.mode.local.auto=true; //开启本地mr
//设置local mr的最大输入数据量,当输入数据量小于这个值时采用local mr的方式,默认为134217728,即128M
set hive.exec.mode.local.auto.inputbytes.max=;
//设置local mr的最大输入文件个数,当输入文件个数小于这个值时采用local mr的方式,默认为4
set hive.exec.mode.local.auto.input.files.max=;
3,表的优化:
a>大小表的join:
新版的hive已经对小表JOIN大表和大表JOIN小表进行了优化。小表放在左边和右边已经没有明显区别。
b>大表join大表:
空key过滤:空key对应的数据无意义
select n.* from (select * from nullidtable where id is not null ) n left join ori o on n.id = o.id;
空key转换:空key对应的数据还是有意义,需要保留
#为空key赋予随机值,在进入reduce的时候防止空key太多而造成数据倾斜
select n.* from nullidtable n full join ori o on
case when n.id is null then concat('hive', rand()) else n.id end = o.id;
c>MapJoin(小表join大表)
#默认开启
set hive.auto.convert.join = true; 默认为true
#大表小表的阈值设置(默认25M以下认为是小表)可以调整
set hive.mapjoin.smalltable.filesize=;
d>group by:
默认情况下,Map阶段同一个key数据分发到同一个reduce,当一个key的数据过大时就会出现数据倾斜。
#是否在Map端进行聚合,默认为True
set hive.map.aggr = true#在Map端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = #有数据倾斜的时候进行负载均衡(默认是false)
set hive.groupby.skewindata = true
当设置为负载均衡之后,生成的计划会有两个MR的job。第一个MRjob,Map的输出结果可能会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MRjob再根据预处理的数据结果按照Group By Key分布到Reduce中(这个过程可以保证相同的Group By Key被分布到同一个Reduce中),最后完成最终的聚合操作。
e>Count(distinct)去重统计
数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT的全聚合操作,即使设定了reduce task个数,set mapred.reduce.tasks=100;hive也只会启动一个reducer,这就造成一个Reduce处理的数据量太大,导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替换:
#设置reduce个数为5
set mapreduce.job.reduces = ;
#采用distinct去重
select count(distinct id) from bigtable;
#采用group by去重
select count(id) from (select id from bigtable group by id) a;
虽然会多用一个Job来完成,但在数据量大的情况下,这个绝对是值得的。
f>笛卡尔积
尽量避免笛卡尔积,join的时候不加on条件,或者无效的on条件,Hive只能使用1个reducer来完成笛卡尔积。
g>行列过滤
列处理:在select中,只拿需要的列,如果有,尽量使用分区过滤,少用select *。
行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在where后面,那么就会先全表关联,之后再过滤。
#先关联再过滤
select o.id from bigtable b join ori o on o.id = b.id
#先过滤再关联
select b.id from bigtable b
join (select id from ori where id <= ) o on b.id = o.id;
h>动态分区
()开启动态分区功能(默认true,开启)
set hive.exec.dynamic.partition=true
()设置为非严格模式(动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。)
set hive.exec.dynamic.partition.mode=nonstrict
()在所有执行MR的节点上,最大一共可以创建多少个动态分区。默认1000
set hive.exec.max.dynamic.partitions=
()在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值100,则会报错。
set hive.exec.max.dynamic.partitions.pernode=
()整个MR Job中,最大可以创建多少个HDFS文件。默认100000
set hive.exec.max.created.files=
()当有空分区生成时,是否抛出异常。一般不需要设置。默认false
set hive.error.on.empty.partition=false
i>分区
分区表实际上就是对应一个HDFS文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。Hive中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据集。在查询时通过WHERE子句中的表达式选择查询所需要的指定的分区,这样的查询效率会提高很多。
j>分桶
分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区。对于一张表或者分区,Hive 可以进一步组织成桶,也就是更为细粒度的数据范围划分。分区针对的是数据的存储路径;分桶针对的是数据文件。
#创建分桶表
create table stu_buck(id int, name string)
clustered by(id)
into 4 buckets
row format delimited fields terminated by '\t';
#创建中间表
create table stu(id int, name string) row format delimited fields terminated by '\t';
#导入数据到中间表
load data local inpath '/opt/module/datas/student.txt' into table stu;
#开启分桶
set hive.enforce.bucketing=true;
#设置reduce数量为-1
set mapreduce.job.reduces=-1;
#向分桶表中导入数据
insert into table stu_buck select id, name from stu;
4,合理设置Map的数量和Reduce的数量
a>复杂文件增加map数量
增加map的方法为:根据computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M公式,调整maxSize最大值。
让maxSize最大值低于blocksize就可以增加map的个数。
set mapreduce.input.fileinputformat.split.maxsize=100;
b>小文件进行合并
#设置为CombineHiveInputFormat合并小文件
set hive.input.format= org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
#在map-only任务结束时合并小文件,默认true
set hive.merge.mapfiles = true;
#在map-reduce任务结束时合并小文件,默认false
set hive.merge.mapredfiles = true;
#合并文件的大小,默认256M
set hive.merge.size.per.task = ;
#当输出文件的平均大小小于该值时,启动一个独立的map-reduce任务进行文件merge
set hive.merge.smallfiles.avgsize = ;
c>合理设置reduce的个数
1.调整reduce个数方法一
()每个Reduce处理的数据量默认是256MB
hive.exec.reducers.bytes.per.reducer=
()每个任务最大的reduce数,默认为1009
hive.exec.reducers.max=
()计算reducer数的公式
N=min(参数2,总输入数据量/参数1)
2.调整reduce个数方法二
在hadoop的mapred-default.xml文件中修改
设置每个job的Reduce个数
set mapreduce.job.reduces = ;
3.reduce个数并不是越多越好
)过多的启动和初始化reduce也会消耗时间和资源;
)另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;
在设置reduce个数的时候也需要考虑这两个原则:处理大数据量利用合适的reduce数;使单个reduce任务处理数据量大小要合适;
5,并行执行
Hive会将一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。或者Hive执行过程中可能需要的其他阶段。默认情况下,Hive一次只会执行一个阶段。不过,某个特定的job可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个job的执行时间缩短。不过,如果有更多的阶段可以并行执行,那么job可能就越快完成。
set hive.exec.parallel=true; //打开任务并行执行
set hive.exec.parallel.thread.number=; //同一个sql允许最大并行度,默认为8。
在共享集群中,需要注意下,如果job中并行阶段增多,那么集群利用率就会增加。当然,得是在系统资源比较空闲的时候才有优势,否则,没资源,并行也起不来。
6,严格模式
通过设置属性hive.mapred.mode值为默认是非严格模式nonstrict 。开启严格模式需要修改hive.mapred.mode值为strict,开启严格模式可以禁止3种类型的查询。
1)对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。(就是用户不允许扫描所有分区)
2)对于使用了order by语句的查询,要求必须使用limit语句。 因为order by为了执行排序过程会将所有的结果数据分发到同一个Reducer中进行处理,强制要求用户增加这个LIMIT语句可以防止Reducer额外执行很长一段时间。
3)限制笛卡尔积的查询。
7,JVM重用
JVM重用是Hadoop调优参数的内容,其对Hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或task特别多的场景,这类场景大多数执行时间都很短。
在Hadoop的mapred-site.xml文件中进行配置
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value></value>
<description>How many tasks to run per jvm. If set to -, there is no limit</description>
</property>
8,推测执行
Hadoop的mapred-site.xml文件中进行配置,默认是true
<property>
<name>mapreduce.map.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some map tasks may be executed in parallel.</description>
</property>
<property>
<name>mapreduce.reduce.speculative</name>
<value>true</value>
<description>If true, then multiple instances of some reduce tasks may be executed in parallel.</description>
</property>
不过hive本身也提供了配置项来控制reduce-side的推测执行:默认是true
<property>
<name>hive.mapred.reduce.tasks.speculative.execution</name>
<value>true</value>
<description>Whether speculative execution for reducers should be turned on. </description>
</property>
不建议开启:(1)任务间存在严重的负载倾斜;(2)特殊任务,比如任务向数据库中写数据。
9,压缩
见第一章
10,explain执行计划
利用explain查看sql的执行计划
Hive的压缩存储和简单优化的更多相关文章
- mongo 固定集合,大文件存储,简单优化 + 三招解决MongoDB的磁盘IO问题
1.固定集合 > db.createCollection(, max:});//固定集合 必须 显式创建. 设置capped为true, 集合总大小xxx字节, [集合中json个数max] { ...
- 一文彻底搞懂Hive的数据存储与压缩
目录 行存储与列存储 行存储的特点 列存储的特点 常见的数据格式 TextFile SequenceFile RCfile ORCfile 格式 数据访问 Parquet 测试 准备测试数据 存储空间 ...
- Hive(八)Hive的Shell操作与压缩存储
一.Hive的命令行 1.Hive支持的一些命令 Command Description quit Use quit or exit to leave the interactive shell. s ...
- 移动互联网实战--资源类APP的数据存储处理和优化
前言: 对于资源类的APP, 其音频/图形占据了APP本身很大的比例. 如何存储和管理这些资源文件, 成了一个颇具挑战性的难点. 移动端的碎片化, 高中低端手机的并存, 需要开发者不光是具备基础的存储 ...
- linux简单优化
1.简单优化 #关闭firewalld,selinux,NetworkManager systemctl(管理服务的命令) stop(关服务) firewalld (服务名称,d是demo的意思) s ...
- C++ 特殊矩阵的压缩存储算法
1. 前言 什么是特殊矩阵? C++,一般使用二维数组存储矩阵数据. 在实际存储时,会发现矩阵中有许多值相同的数据或有许多零数据,且分布呈现出一定的规律,称这类型的矩阵为特殊矩阵. 为了节省存储空间, ...
- 双数组trie树的基本构造及简单优化
一 基本构造 Trie树是搜索树的一种,来自英文单词"Retrieval"的简写,可以建立有效的数据检索组织结构,是中文匹配分词算法中词典的一种常见实现.它本质上是一个确定的有限状 ...
- MySQL存储引擎简单介绍
MySQL使用的是插件式存储引擎. 主要包含存储引擎有:MyISAM,Innodb,NDB Cluster,Maria.Falcon,Memory,Archive.Merge.Federated. 当 ...
- mysql简单优化思路
mysql简单优化思路 作为开发人员,数据库知识掌握的可能不是很深入,但是一些基本的技能还是要有时间学习一下的.作为一个数据库菜鸟,厚着脸皮来总结一下 mysql 的基本的不能再基本的优化方法. 为了 ...
随机推荐
- 【雕爷学编程】Arduino动手做(6)---声音传感器模块
37款传感器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止37种的.鉴于本人手头积累了一些传感器,依照实践(动手试试)出真知的理念,以学习和交流为目的,这里准备逐一做做实验 ...
- Vue Element-UI使用第三方icon图标(转)
转载自:https://www.jianshu.com/p/59dd28f0b9c9 1.打开阿里icon,注册 >登录>图标管理>我的项目 2.新建项目 3. 添加icon到项 ...
- 【Django】rest_framework 序列化自定义替换返回值
# 序列化设置 class PagerSerialiser(serializers.ModelSerializer): name = serializers.CharField(source=&quo ...
- Kali Linux 2020.1安装以及安装后要做的事
Kali Linux是基于Debian的Linux发行版,预装了许多渗透测试软件,让大家从各种繁琐的软件安装中解脱出来,专注于测试本身. 本文章介绍了如何安装目前最新的2020.1版本,以及安装好后补 ...
- 201771010128王玉兰《面向对象程序设计(Java)》第十周学习总结
第一部分:理论知识部分总结: (1) 定义简单泛型类: A:泛型:也称参数化类型(parameterizedtype),就是在定义类.接口和方法时,通过类型参数指 示将要处理的对象类型. B:泛型程序 ...
- 为什么Tableviewcell创建时可以不判空
dequeueReuseableCellWithIdentifier:与dequeueReuseableCellWithIdentifier:forIndexPath:的区别: 前者不必向tableV ...
- poj3177 无向连通图加多少条边变成边双连通图
Redundant Paths Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 15752 Accepted: 6609 ...
- HDU6440 Dream
题目链接:https://vjudge.net/problem/HDU-6440 知识点: 构造.费马小定理 题目大意: 给定一个素数 $p$,要求定义一个加法运算表和一个乘法运算表,尺寸都为 $p ...
- vim的基础命令
:q 退出 :wq 保存并退出 :q! 不保存并退出 :w 保存 :w! 强行保存
- EL表达式用法---查询博客
jsp脚本:<%=request.getAttribute(name)%>EL表达式替代上面的脚本:${requestScope.name} 使用EL最主要的作用是获得四大域中的数据,格式 ...