Hive优化笔记
1.hive参数优化
1.1 map个数优化
map的个数是如何决定的:
mapred.min.split.size: 数据的最小分割单元大小,默认值是1B
mapred.max.split.size: 数据的最大分割单元大小,默认值是256MB
一个文件在执行数据处理的时候,被分成文件的个数如下:
if(一个文件的大小 <= mapred.max.split.size) {
该文件生成一个map
} else {
一个文件的产生的map的个数 = (文件大小 / mapred.max.split.size) + 1
}
1.1.1 减少map个数:
set mapred.max.split.size=256000000; // -- 决定每个map处理的最大的文件大小 单位为B
set mapred.min.split.size.per.node=100000000;//每个节点处理的最小split
set mapred.min.split.size.per.rack=100000000;//每个机架处理的最小slit
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;// 默认开启
1.文件大于256MB的进行分割;
2.那些小于256MB的(包括分割大文件剩下的)进行合并;
备注:
a.四个参数的配置结果大小要满足如下关系。
max.split.size >= min.split.size >= min.size.per.node >= min.size.per.node
b.四个参数的作用优先级分别如下
max.split.size <= min.split.size <= min.size.per.node <= min.size.per.node
1.1.2 增加map的个数
a.调节mapred.max.split.size的大小可以达到调整map个数的效果,直接调整mapred.map.tasks这个参数是没有效果的。
b.拆分文件
如果一个文件为100MB,属性字段很少,结果数据量却很大(如1000万),使用a方案任然生成一个map,那么可以手动将文件拆分成多个。
set mapred.reduce.tasks=100;
create table tableName_1 as
select * from tableName t
distribute by rand(t.name);
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;
1.2 reduce个数优化
多少个reduce产生多少个输出文件,reduce个数过大会产生过多的小文件,reduce的启动和销毁也会带来消耗;reduce个数过小,单个reduce处理的数据量过大会导致OOM。
set mapred.reduce.tasks/mapreduce.job.reduces=100
set hive.exec.reducers.bytes.per.reducer = 256123456// 每个reduce处理的数据量,默认为1GB
set hive.exec.reducers.max=1009 // 每个任务最大的reduce数,默认为1009
//如果不设置,hive会根据输入文件估算reduce的个数
2.压缩优化
hive底层使用mapreduce来实现,而mapreduce的中间过程都需要落入磁盘,消耗大量的网络IO和磁盘IO,因此针对IO密集型job,通过增加CPU资源消耗来降低IO资源的消耗,达到提高性能的目的。
压缩方式:
序号 | 压缩格式 | 是否可split | 是否自带 | 压缩率 | 速度 | 是否Hadoop自带 | 对应class |
---|---|---|---|---|---|---|---|
1 | gzip | 否 | 是 | 很高 | 比较快 | 是 | org.apache.hadoop.io.compress.GzipCodec |
2 | lzo | 是 | 是 | 比较高 | 很快 | 否,需要安装 | org.apache.hadoop.io.compress.LzoCodec |
3 | snappy | 否 | 是 | 比较高 | 很快 | 否,需要安装 | org.apache.hadoop.io.compress.SnappyCodec |
4 | bzip2 | 是 | 否 | 最高 | 慢 | 是 | org.apache.hadoop.io.compress.BZip2Codec |
3.存储优化
序号 | 存储格式 | 行列方式 | 说明 |
---|---|---|---|
1 | TextFile | 行式存储 | |
2 | Sequence Files | 行式存储 | 支持Block压缩 |
3 | RCFile | 按行分块,按列存储 | 结合了行存储和列存储的优点 |
4 | ORCFile | 按行分块,按列存储 | RCFile的改良版本 |
5 | parquet | 行式存储 |
一般选择ORCFile/parquet + snappy 的方式
4.表结构
4.1 内部表和外部表
创建表的时候指定external就是外部表,否则就是内部表。
序号 | 表类型 | 管理方 | 数据存储位置 | 元数据 | 修改表结构 |
---|---|---|---|---|---|
1 | 内部表 | Hive自身管理 | /user/hive/warehouse | 内部表删除后元数据和数据都删除 | 直接同步到元数据 |
2 | 外部表 | HDFS管理 | 用户自己通过location指定 | 外部表删除后只删除元数据,不删除hdfs数据 | 需要msck repair table tableName 进行同步到元数据 |
4.2 静态分区和动态分区
静态分区在建表的时候通过PARTITIONED BY定义分区,alter table 添加和删除分区
动态分区:
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nonstrict;
4.2 分桶
分桶通过指定列的数据取hash值将数据进行划分,相同的数据划分到一个桶里,从而减少数据访问量,提高查询效率。
set hive.enforce.bucketing = true
CLUSTERED BY (id) INTO 200 BUCKETS //分桶的列id是表中已有的列
5.sql优化
5.1 小表放到join左边:
将数据量小的表或子查询放在join的左边,因为join操作的reduce阶段,将join左边的表的内容加载进内存,因此将数据量小的表放在左边,可以提高效率,一定程度避免OOM。
5.2 过滤放到关联之前
列过滤:只select需要的字段
行过滤:过滤条件放到子查询里
5.3 开启mapjoin
set hive.auto.convert.join = true
set hive.mapjoin.smalltable.filesize=25123456 // 触发mapjoin的小文件大小的阈值
不指定mapjoin开启的情况,hive会把所有join转换为common join,即mapreduce的时候执行join,可以使用mapjoin将小文件的整个数据加载到内存,在map端进行join,避免reduce处理,一定程度上避免了数据倾斜。
5.4 开启map端聚合
默认情况下,map阶段同一key数据分发给一个reduce,当一个key数据过大时就倾斜了。不是所有的聚合操作都必须在reduce端完成,很多聚合操作都可以先在Map端进行部分聚合,最后在reduce端得出最终结果。
set hive.map.aggr = true; // 默认true
set hive.groupby.mapaggr.checkinterval = 100000; // 在Map端进行聚合操作的条目数目
set hive.groupby.skewindata = true; // 有数据倾斜的时候进行负载均衡,默认false
5.5 使用先GROUP BY再COUNT的方式替换COUNT DISTINCT
数据量大的情况下,由于COUNT DISTINCT操作需要用一个reduce task来完成,这一个reduce需要处理的数据量太大,容易产生倾斜问题。
5.6 查看执行计划
explain sql // 查看执行计划
explain extended // 查看详细执行计划
6.其他优化
6.1 Fetch抓取
fetch抓取开启一定程度上可以避免触发mapreduce,主要针对全局查找(select *),字段查找(select field),limit(limit 100)等
开启方式:
set hive.fetch.task.conversion=more //关闭:none, 开启(默认):more
6.2 执行模式
6.2.1 本地模式
set hive.exec.mode.local.auto=true
主要针对小数据量和测试使用,即在单台机器上处理所有任务,避免在Hadoop集群上启动耗时的问题。
6.2.2 并行模式
set hive.exec.parallel=true //或者通过配置文件来完成,非相互依赖的阶段并行执行,否则默认情况下,Hive一次只会执行一个阶段。
6.2.3 严格模式
set hive.mapred.mode=strict // 默认关闭
对于分区表,禁止不指定分区查询
order by 必须有limit
禁止笛卡尔积查询
6.3 JVM重用
set mapred.job.reuse.jvm.num.tasks=15;
JVM重用可以使得JVM实例在同一个job中重新使用N次,N值可配置,通常在10~20之间,也可在mapred-site.xml文件中。
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>15</value>
</property>
缺点:JVM不是立即销毁,空闲的时候会导致资源浪费。