总结了一下在以往工作中,对于 Hive SQL
调优的一些理论利用,是日常积攒的一些优化技巧,如有出入,欢送在评论区留言探讨~
EXPLAIN 查看执行打算
建表优化
分区
- 分区表基本操作,partitioned
- 二级分区
- 动静分区
分桶
- 分桶表基本操作,clustered
- 分桶表次要是抽样查问,找出具备代表性的后果
抉择适合的文件格式和压缩格局
- LZO,拉兹罗
- Snappy
- 压缩速度快,压缩比高
HiveSQL 语法优化
单表查问优化
-
列裁剪和分区裁剪,全表和全列扫描效率都很差,生产环境相对不要应用
SELECT *
,所谓列裁剪就是在查问时只读取须要的列,分区裁剪就是只读取须要的分区- 与列裁剪优化相干的配置项是
hive.optimize.cp
,默认是 true - 与分区裁剪优化相干的则是
hive.optimize.pruner
,默认是 true - 在
HiveSQL
解析阶段对应的则是ColumnPruner
逻辑优化器
- 与列裁剪优化相干的配置项是
-
Group By 配置调整,
map
阶段会把同一个key
发给一个reduce
,当一个key
过大时就歪斜了,能够开启map
端预聚合,能够无效缩小shuffle
数据量并# 是否在 map 端聚合,默认为 true set hive.map.aggr = true; # 在 map 端聚合的条数 set hive.groupby.mapaggr.checkintervel = 100000; # 在数据歪斜的时候进行平衡负载(默认是 false),开启后会有 两个 `mr 工作 `。# 当选项设定为 true 时,第一个 `mr 工作 ` 会将 map 输入的后果随机调配到 `reduce`,# 每个 `reduce` 会随机散布到 `reduce` 上,这样的处理结果是会使雷同的 `group by key` 分到不同的 `reduce` 上。# 第二个 `mr 工作 ` 再依据预处理的后果按 `group by key` 分到 `reduce` 上,# 保障雷同 `group by key` 的数据分到同一个 `reduce` 上。# * 切记!!!* # 这样能解决数据歪斜,然而不能让运行速度更快 # 在数据量小的时候,开始数据歪斜负载平衡可能反而会导致工夫变长 # 配置项毕竟是死的,单纯靠它有时不能基本上解决问题 # 因而还是倡议自行理解数据歪斜的细节,并优化查问语句 set hive.groupby.skewindata = true;
-
Vectorization,矢量计算技术,通过设置批处理的增量大小为 1024 行单次来达到比单行单次更好的效率
# 开启矢量计算 set hive.vectorized.execution.enabled = true; # 在 reduce 阶段开始矢量计算 set hive.vectorized.execution.reduce.enabled = true;
- 多重模式,一次读取屡次插入,同一张表的插入操作优化成先
from table
再insert
- in/exists 或者 join 用
left semi join
代替(为什么代替扩大一下~)
多表查问优化
-
CBO 优化,老本优化器,代价最小的执行打算就是最好的执行打算
- join 的时候表的程序关系,后面的表都会被加载到内存中,前面的表进行磁盘扫描
- 通过
hive.cbo.enable
,主动优化 hivesql 中多个 join 的执行程序 -
能够通过查问一下参数,这些个别都是 true,无需批改
set hive.cbo.enable = true; set hive.compute.query.using.stats = true; set hive.stats.fetch.column.stats = true; set hive.stats.fetch.partition.stats = true;
-
谓词下推(十分要害的一个优化 ),将
sql
语句中的where
谓词逻辑都尽可能提前执行,缩小上游解决的数据量,
在关系型数据库如 MySQL 中,也有谓词下推(Predicate Pushdown,PPD)
的概念,
它就是将sql
语句中的where
谓词逻辑都尽可能提前执行,缩小上游解决的数据量# 这个设置是默认开启的 # 如果敞开了然而 cbo 开启,那么敞开仍然不会失效 # 因为 cbo 会主动应用更为高级的优化打算 # 与它对应的逻辑优化器是 PredicatePushDown # 该优化器就是将 OperatorTree 中的 FilterOperator 向上提 set hive.optimize.pdd = true; # 举个例子 # 对 forum_topic 做过滤的 where 语句写在子查问外部,而不是内部 select a.uid,a.event_type,b.topic_id,b.title from calendar_record_log a left outer join ( select uid,topic_id,title from forum_topic where pt_date = 20220108 and length(content) >= 100 ) b on a.uid = b.uid where a.pt_date = 20220108 and status = 0;
-
Map Join,
map join
是指将join
操作两方中比拟小的表间接散发到各个map
过程的内存中,在map
中进行join
的操作。
map join
特地适宜大小表 join
的状况,Hive 会将build table
和probe table
在map
端间接实现join
过程,毁灭了reduce
,缩小shuffle
,所以会缩小开销set hive.auto.convert.join = true
,配置开启,默认是 true- 留神!!! 如果执行
小表 join 大表
,小表作为主连贯的主表,所有数据都要写出去,此时会走reduce
阶段,mapjoin
会生效 大表 join 小表
不受影响,上一条的起因次要是因为小表 join 大表
的时候,map
阶段不晓得reduce
的后果其余reduce
是否有,-
所以必须在最初
reduce
聚合的时候再解决,就产生了reduce
的开销# 举个例子 # 在最常见的 `hash join` 办法中,个别总有一张绝对小的表和一张绝对大的表,# 小表叫 `build table`,大表叫 `probe table` # Hive 在解析带 join 的 SQL 语句时,会默认将最初一个表作为 `probe table`,# 将后面的表作为 `build table` 并试图将它们读进内存 # 如果表程序写反,`probe table` 在后面,引发 `OOM(内存不足)` 的危险就高了 # 在维度建模数据仓库中,事实表就是 `probe table`,维度表就是 `build table` # 假如当初要将日历记录事实表和记录项编码维度表来 `join` select a.event_type,a.event_code,a.event_desc,b.upload_time from calendar_event_code a inner join ( select event_type,upload_time from calendar_record_log where pt_date = 20220108 ) b on a.event_type = b.event_type;
-
Map Join,大表和大表的
MapReduce 工作
,能够应用SMB Join
- 间接 join 耗时会很长,然而依据某字段分桶后,两个大表每一个桶就是一个小文件,两个表的每个小文件的分桶字段都应该可能一一对应(hash 值取模的后果)
-
总结就是分而治之,留神两个大表的分桶字段和数量都应该保持一致
set hive.optimize.bucketmapjoin = true; set hive.optimeize.bucketmapjoin.sortedmerge = true; hive.input.format = org.apache.hadoop.hive.ql.io.BucketizedHiveInputFormat;
-
多表 join 时 key 雷同,这种状况会将多个
join
合并为一个mr 工作
来解决# 举个例子 # 如果上面两个 join 的条件不雷同 # 比方改成 a.event_code = c.event_code # 就会拆成两个 MR job 计算 select a.event_type,a.event_code,a.event_desc,b.upload_time from calendar_event_code a inner join ( select event_type,upload_time from calendar_record_log where pt_date = 20220108 ) b on a.event_type = b.event_type inner join ( select event_type,upload_time from calendar_record_log_2 where pt_date = 20220108 ) c on a.event_type = c.event_type;
- 笛卡尔积,在生产环境中严禁应用
其余查问优化
-
Sort By 代替 Order By,HiveQL 中的
order by
与其余sql
方言中的性能一样,就是将后果按某字段全局排序,这会导致所有map
端数据都进入一个reducer
中,
在数据量大时可能会长工夫计算不完。如果应用sort by
,那么还是会视状况启动多个 reducer 进行排序
,并且保障每个reducer
内部分有序。
为了管制map
端数据调配到reducer
的key
,往往还要配合distribute by
一起应用,如果不加distribute by
的话,map
端数据就会随机调配到reducer
# 举个例子 select uid,upload_time,event_type,record_data from calendar_record_log where pt_date >= 20220108 and pt_date <= 20220131 distribute by uid sort by upload_time desc,event_type desc;
- Group By 代替 Distinct,当要统计某一列的去重数时,如果数据量很大,
count(distinct)
就会十分慢,起因与order by
相似,
count(distinct)
逻辑只会有很少的reducer
来解决。然而这样写会启动两个mr 工作
(单纯 distinct 只会启动一个),
所以要确保数据量大到启动mr 工作
的overhead
远小于计算耗时,才思考这种办法,当数据集很小或者key
的歪斜比拟显著时,group by
还可能会比distinct
慢
数据歪斜
留神要和数据适量的状况辨别开,数据歪斜是大部分工作都曾经执行结束,然而某一个工作或者少数几个工作,始终未能实现,甚至执行失败,
而数据适量,是大部分工作都执行的很慢,这种状况须要通过裁减执行资源的形式来加快速度,大数据编程不怕数据量大,就怕数据歪斜,一旦数据歪斜,重大影响效率
单表携带了 Group By 字段的查问
-
工作中存在
group by
操作,同时聚合函数为count
或sum
,单个key
导致的数据歪斜能够这样通过设置开启map
端预聚合参数的形式来解决# 是否在 map 端聚合,默认为 true set hive.map.aggr = true; # 在 map 端聚合的条数 set hive.groupby.mapaggr.checkintervel = 100000; # 有数据歪斜的时候开启负载平衡,这样会生成两个 mr 工作 set hive.groupby.skewindata = true;
-
工作中存在
group by
操作,同时聚合函数为count
或sum
,多个key
导致的数据歪斜能够通过减少reduce
的数量来解决- 减少分区能够缩小不同分区之间的数据量差距,而且减少的分区时候不能是之前分区数量的倍数,不然会导致取模后果雷同持续分在雷同分区
-
第一种批改形式
# 每个 reduce 解决的数量 set hive.exec.reduce.bytes.per.reducer = 256000000; # 每个工作最大的 reduce 数量 set hive.exec.reducers.max = 1009; # 计算 reducer 数的公式,依据工作的须要调整每个工作最大的 reduce 数量 N = min(设置的最大数,总数量数 / 每个 reduce 解决的数量)
-
第二种批改形式
# 在 hadoop 的 mapred-default.xml 文件中批改 set mapreduce.job.reduces = 15;
两表或多表的 join 关联时,其中一个表较小,然而 key 集中
-
设置参数减少
map
数量# join 的 key 对应记录条数超过该数量,会进行分拆 set hive.skewjoin.key = 1000; # 并设置该参数为 true,默认是 false set hive.optimize.skewjoin = true; # 下面的参数如果开启了会将计算数量超过阈值的 key 写进临时文件,再启动另外一个工作做 map join # 能够通过设置这个参数,管制第二个工作的 mapper 数量,默认 10000 set hive.skewjoin.mapjoin.map.tasks = 10000;
- 应用
mapjoin
,缩小reduce
从根本上解决数据歪斜,参考HiveSQL 语法优化 -> 多表查问优化 -> Map Join,大表和大表的 MapReduce 工作,SMB Join
两表或多表的 join 关联时,有 Null 值 或 无意义值
这种状况很常见,比方当 事实表是日志类数据
时,往往会有一些项没有记录到,咱们视状况会将它置为 null
,或者 空字符串
、-1
等,
如果缺失的项很多,在做 join
时这些空值就会十分集中,连累进度,因而,若不须要空值数据,就提前写 where 语句过滤掉,
须要保留的话,将空值 key 用随机形式打散,例如将 用户 ID 为 null 的记录随机改为负值:
select a.uid,a.event_type,b.nickname,b.age
from (
select
(case when uid is null then cast(rand()*-10240 as int) else uid end) as uid,
event_type from calendar_record_log
where pt_date >= 20220108
) a left outer join (select uid,nickname,age from user_info where status = 4) b on a.uid = b.uid;
两表或多表的 join 关联时,数据类型不对立
比方 int
类型和 string
类型进行关联,关联时候以小类型作为分区,这里 int
、string
会到一个 reduceTask
中,如果数据量多,会造成数据歪斜
# 能够通过转换为同一的类型来解决
cast(user.id as string)
独自解决歪斜 key
这其实是下面解决空值办法的拓展,不过歪斜的 key
变成了有意义的,一般来讲歪斜的 key
都很少,咱们能够将它们抽样进去,
对应的行独自存入长期表中,而后打上一个较小的随机数前缀(比方0~9
),最初再进行聚合
Hive Job 优化
Hive Map 优化
Map 数量多少的影响
-
Map 数过大
map
阶段输入文件太小,产生大量小文件- 初始化和创立
map
的开销很大
-
Map 数太小
- 文件解决或查问并发度小,
Job
执行工夫过长 - 大量作业时,容易梗塞集群
- 文件解决或查问并发度小,
管制 Map 数的准则
依据理论状况,管制 map
数量须要遵循两个准则
- 第一是使大数据量利用适合的
map
数 - 第二是使单个
map
工作解决适合的数据量
简单文件适当减少 Map 数
- 当
input
的文件都很大,工作逻辑简单,map
执行十分慢的时候,能够思考减少map
数,来使得每个map
解决的数据量缩小,从而进步工作的执行效率 - 那么如何减少
map
的数量呢?在map
阶段,文件先被切分成split
块,而后每一个split
切片对应一个Mapper 工作
,
FileInputFormat
这个类先对输出文件进行逻辑上的划分,以128m
为单位,将原始数据从逻辑上宰割成若干个split
,每个split
切片对应一个mapper 工作
,
所以说缩小切片的大小就可减少map
数量 - 能够根据公式计算
computeSliteSize(Math.max(minSize, Math.min(maxSize, blockSize))) = blockSize = 128m
- 执行语句:
set mapreduce.input.fileinputformat.split.maxsize = 100;
小文件进行合并缩小 Map 数
为什么要进行小文件合并?因为如果一个工作有很多小文件(远远小于块大小 128m),则每个小文件也会被当做一个块,用一个 map
工作来实现,
而一个 map
工作启动和初始化的工夫远远大于逻辑解决的工夫,就会造成很大的资源节约,同时可执行的 map
数是受限的
两种形式合并小文件
-
在
Map 执行前
合并小文件,缩小map
数量// 每个 Map 最大输出大小(这个值决定了合并后文件的数量) set mapred.max.split.size = 256000000; // 一个节点上 split 的至多的大小(这个值决定了多个 DataNode 上的文件是否须要合并) set mapred.min.split.size.per.node = 100000000; // 一个交换机下 split 的至多的大小(这个值决定了多个交换机上的文件是否须要合并) set mapred.min.split.size.per.rack = 100000000; // 执行 Map 前进行小文件合并 set hive.input.format = org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
-
在
Map-Reduce 工作执行完结时
合并小文件,缩小小文件输入// 设置 map 端输入进行合并,默认为 true set hive.merge.mapfiles = true; // 设置 reduce 端输入进行合并,默认为 false set hive.merge.mapredfiles = true; // 设置合并文件的大小,默认是 256 set hive.merge.size.per.task = 256 * 1000 * 1000; // 当输入文件的均匀大小小于该值时,启动一个独立的 `MapReduce 工作 ` 进行文件 `merge`。set hive.merge.smallfiles.avgsize = 16000000;
Map 端预聚合缩小 Map 数量
- 相当于在
map
端执行combiner
,执行命令:set hive.map.aggr = true;
combiners
是对map
端的数据进行适当的聚合,其益处是缩小了从map
端到reduce
端的数据传输量- 其作用的实质,是将
map
计算的后果进行二次聚合,使Key-Value<List>
中List
的数据质变小,从而达到缩小数据量的目标
揣测执行
- 在分布式集群环境下,因为程序 Bug(包含 Hadoop 自身的 bug),负载不平衡或者资源散布不均等起因,会造成同一个作业的多个工作之间运行速度不统一,
有些工作的运行速度可能显著慢于其余工作(比方一个作业的某个工作进度只有 50%,而其余所有工作曾经运行结束),则这些工作会拖慢作业的整体执行进度 - Hadoop 采纳了
揣测执行(Speculative Execution)
机制,它依据肯定的法令揣测出拖后腿的工作,并为这样的工作启动一个备份工作,
让该工作与原始工作同时解决同一份数据,并最终选用最先胜利运行实现工作的计算结果作为最终后果 - 执行命令:
set mapred.reduce.tasks.speculative.execution = true; # 默认是 true
- 当然,如果用户对于运行时的偏差十分敏感的话,那么能够将这些性能敞开掉,如果用户因为输出数据量很大而须要执行长时间的
map task
或者reduce task
的话,
那么启动揣测执行造成的节约是十分微小的
正当管制 Map 数量的理论案例
假如一个 SQL 工作:
SELECT COUNT(1)
FROM fx67ll_alarm_count_copy
WHERE alarm_date = "2021-01-08";
该工作的输出目录 inputdir
是:/group/fx67ll_data/fx67ll_data_etl/date/fx67ll_alarm_count_copy/alarm_date=2021-01-08
,共有 194 个文件,
其中很多是远远小于 128m
的小文件,总大小约 9G
,失常执行会用194 个 Map 工作
,map
总共耗费的计算资源:SLOTS_MILLIS_MAPS= 610,023
通过在 Map 执行前合并小文件,缩小 Map 数
# 后面三个参数确定合并文件块的大小
# 大于文件块大小 128m 的,依照 128m 来分隔
# 小于 128m, 大于 100m 的,依照 100m 来分隔
# 把那些小于 100m 的(包含小文件和分隔大文件剩下的),进行合并,最终生成了 74 个块
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= 323,098
,对于这个简略 SQL 工作,执行工夫上可能差不多,但节俭了一半的计算资源
再假如这样一个 SQL 工作:
SELECT data_fx67ll,
COUNT(1),
COUNT(DISTINCT id),
SUM(CASE WHEN …),
SUM(CASE WHEN …),
SUM(…)
FROM fx67ll_device_info_zs
GROUP data_fx67ll
如果表 fx67ll_device_info_zs
只有一个文件,大小为 120m
,但蕴含几千万的记录,如果用 1 个map
去实现这个工作,必定是比拟耗时的,
这种状况下,咱们要思考将这一个文件正当的拆分成多个
减少 Reduce 数量,来减少 Map 数量
set mapred.reduce.tasks=10;
CREATE TABLE fx67ll_device_info_zs_temp
AS
SELECT *
FROM fx67ll_device_info_zs
DISTRIBUTE BY RAND(123);
这样会将 fx67ll_device_info_zs
表的记录,随机的扩散到蕴含 10 个文件的 fx67ll_device_info_zs_temp
表中,
再用 fx67ll_device_info_zs_temp
代替下面 sql
中的 fx67ll_device_info_zs
表,
则会用 10 个 map
工作去实现,每个 map
工作解决大于 12m(几百万记录)
的数据,效率必定会好很多
Hive Reduce 优化
Reduce 数量多少的影响
- 同
map
一样,启动和初始化reduce
也会耗费工夫和资源 - 另外,有多少个
reduce
,就会有多少个输入文件,如果生成了很多个小文件,那么如果这些小文件作为下一个工作的输出,则也会呈现小文件过多的问题
管制 Reduce 数的准则
和 map
一样,管制 reduce
数量须要遵循两个准则
- 第一是使大数据量利用适合的
reduce
数 - 第二是使单个
reduce
工作解决适合的数据量
Hive 本人如何确定 Reduce 数
reduce
个数的设定极大影响工作执行效率,不指定 reduce
个数的状况下,Hive 会猜想确定一个 reduce
个数,基于以下两个设定:
# 每个 reduce 工作解决的数据量,默认为 1000^3=1G
hive.exec.reducers.bytes.per.reducer
# 每个工作最大的 reduce 数,默认为 999
hive.exec.reducers.max
计算 reducer
数的公式很简略 N = min(参数 2,总输出数据量 / 参数 1)
即,如果 reduce
的输出(map
的输入)总大小不超过 1G,那么只会有一个 reduce
工作
举个例子:
SELECT alarm_date,
COUNT(1)
FROM fx67ll_alarm_count_copy
WHERE alarm_date = "2021-01-08"
GROUP BY alarm_date;
该工作的输出目录 inputdir
是:/group/fx67ll_data/fx67ll_data_etl/date/fx67ll_alarm_count_copy/alarm_date=2021-01-08
,
总大小为 9G
多,因而这句有 10 个reduce
如何调整 Reduce 数量
留神!!!理论开发中,reduce 的个数个别通过程序主动推定,而不人为干预,因为人为管制的话,如果使用不当很容易造成后果不精确,且升高执行效率
-
通过调整每个
reduce
工作解决的数据量来调整reduce
个数,解决的数据量少了,工作数就多了# 设置每个 reduce 工作解决的数据量 500M,默认是 1G set hive.exec.reducers.bytes.per.reducer = 500000000; SELECT alarm_date, COUNT(1) FROM fx67ll_alarm_count_copy WHERE alarm_date = "2021-01-08" GROUP BY alarm_date; 这次有 20 个 reduce
-
间接调整每个
Job
中的最大reduce
数量,过于简略粗犷,慎用,尽量不要,尽管设置了reduce
的个数看起来如同执行速度变快了,然而理论并不是这样的# 设置每个工作最大的 reduce 数为 15 个,默认为 999 set mapred.reduce.tasks = 15; SELECT alarm_date, COUNT(1) FROM fx67ll_alarm_count_copy WHERE alarm_date = "2021-01-08" GROUP BY alarm_date; 这次有 15 个 reduce
揣测执行
参考 map 优化的最初一项
什么状况下只有一个 Reduce
很多时候你会发现工作中不论数据量多大,不论你有没有设置调整 reduce
个数的参数,工作中始终都只有一个 reduce
工作,
其实只有一个 reduce
工作的状况,除了数据量小于 hive.exec.reducers.bytes.per.reducer
参数值的状况外,还有以下起因:
-
没有
Group By
的汇总,例如:SELECT alarm_date, COUNT(1) FROM fx67ll_alarm_count_copy WHERE alarm_date = "2021-01-08" GROUP BY alarm_date; 写成 SELECT COUNT(1) FROM fx67ll_alarm_count_copy WHERE alarm_date = "2021-01-08"; 留神防止这样状况的产生
- 用了
Order by
排序,因为它会对数据进行全局排序,所以数据量特地大的时候效率非常低,尽量避免 - 有笛卡尔积,生产环境必须严格防止
Hive 工作整体优化
Fetch 抓取
Fetch 抓取
是指 Hive 在某些状况的查问能够不用应用 mr 工作
,例如在执行一个简略的select * from XX
时,咱们只须要简略的进行抓取对应目录下的数据即可。
在 hive-default.xml.template
中,hive.fetch.task.conversion(默认是 morn)
,老版本中默认是 minimal
。
该属性为 morn
时,在全局查找,字段查找,limit 查找等都不走mr 工作
本地模式
Hive 也能够不将工作提交到集群进行运算,而是间接在一台节点上解决,因为打消了提交到集群的 overhead,所以比拟适宜数据量很小,且逻辑不简单的工作。
设置 hive.exec.mode.local.auto
为 true 能够开启本地模式,但工作的输出数据总量必须小于 hive.exec.mode.local.auto.inputbytes.max(默认值 128MB)
,
且 mapper 数必须小于 hive.exec.mode.local.auto.tasks.max(默认值 4)
,reducer
数必须为 0 或 1
,才会真正用本地模式执行
并行执行
Hive 中相互没有依赖关系的 job
间是能够并行执行的,最典型的就是多个子查问 union all
,
在集群资源绝对短缺的状况下,能够开启并行执行,行将参数 hive.exec.parallel
设为 true,
另外 hive.exec.parallel.thread.number
能够设定并行执行的线程数,默认为 8,个别都够用。
留神!!!没资源无奈并行,且数据量小时开启可能还没不开启快,所以倡议数据量大时开启
严格模式
要开启严格模式,须要将参数 hive.mapred.mode 设为 strict
。
所谓严格模式,就是强制不容许用户执行 3 种有危险的 sql
语句,一旦执行会间接失败,这 3 种语句是:
- 查问分区表时不限定分区列的语句
- 两表 join 产生了笛卡尔积的语句
- 用 order by 来排序但没有指定 limit 的语句
JVM 重用
- 次要用于解决小文件过多的时候
- 在
mr 工作
中,默认是每执行一个task
就启动一个JVM
,如果task
十分小而碎,那么JVM
启动和敞开的耗时就会很长 - 能够通过调节参数
mapred.job.reuse.jvm.num.tasks
来重用 - 例如将这个参数设成 5,那么就代表同一个
mr 工作
中程序执行的 5 个task
能够重复使用一个JVM
,缩小启动和敞开的开销,但它对不同mr 工作
中的task
有效
启用压缩
压缩 job 的两头后果数据和输入数据,能够用大量 CPU 工夫节俭很多空间,压缩形式个别抉择 Snappy,效率最高。
要启用两头压缩,须要设定 hive.exec.compress.intermediate
为 true,
同时指定压缩形式 hive.intermediate.compression.codec
为org.apache.hadoop.io.compress.SnappyCodec
。
另外,参数 hive.intermediate.compression.type
能够抉择对 块(BLOCK)
还是 记录(RECORD)
压缩,BLOCK 的压缩率比拟高。
输入压缩的配置基本相同,关上 hive.exec.compress.output
即可
采纳适合的存储格局
- 在 Hive SQL 的
create table
语句中,能够应用stored as ...
指定表的存储格局。
Hive 表反对的存储格局有TextFile
、SequenceFile
、RCFile
、Avro
、ORC
、Parquet
等。
存储格局个别须要依据业务进行抉择,在咱们的实操中,绝大多数表都采纳TextFile
与Parquet
两种存储格局之一。 TextFile
是最简略的存储格局,它是纯文本记录,也是 Hive 的默认格局,尽管它的磁盘开销比拟大,查问效率也低,但它更多地是作为跳板来应用。RCFile
、ORC
、Parquet
等格局的表都不能由文件间接导入数据,必须由TextFile
来做直达。Parquet
和ORC
都是 Apache 旗下的开源列式存储格局。列式存储比起传统的行式存储更适宜批量 OLAP 查问
,并且也反对更好的压缩和编码。- 咱们抉择
Parquet
的起因次要是它反对Impala 查问引擎
,并且咱们对update
、delete
和事务性操作
需要很低。
Hive 的小文件
什么状况下会产生小文件?
- 动静分区插入数据,产生大量的小文件,从而导致 map 数量剧增
- reduce 数量越多,小文件也越多,有多少个 reduce,就会有多少个输入文件,如果生成了很多小文件,那这些小文件作为下一次工作的输出
- 数据源自身就蕴含大量的小文件
小文件有什么样的危害?
- 从 Hive 的角度看,小文件会开很多 map,一个 map 开一个 java 虚拟机 jvm 去执行,所以这些工作的初始化,启动,执行会节约大量的资源,重大影响性能
-
在 hdfs 中,每个小文件对象约占 150byte,如果小文件过多会占用大量内存,这样 NameNode 内存容量重大制约了集群的扩大
- 每个 hdfs 上的文件,会耗费 128 字节记录其 meta 信息,所以大量小文件会占用大量内存
如何防止小文件带来的危害?
从小文件产生的途经就能够从源头上管制小文件数量
- 应用 Sequencefile 作为表存储格局,不要用 textfile,在肯定水平上能够缩小小文件
- 缩小 reduce 的数量(能够应用参数进行管制)
-
少用动静分区,用时记得按 distribute by 分区
对于已有的小文件
- 应用 hadoop archive 命令把小文件进行归档,采纳 archive 命令不会缩小文件存储大小,只会压缩 NameNode 的空间应用
- 重建表,建表时缩小 reduce 数量
我是 fx67ll.com,如果您发现本文有什么谬误,欢送在评论区探讨斧正,感谢您的浏览!
如果您喜爱这篇文章,欢送拜访我的 本文 github 仓库地址,为我点一颗 Star,Thanks~ :)
转发请注明参考文章地址,非常感谢!!!