如何开发电子商务网站,聊城网站推广,东莞十大保安公司,企业宣传制作app哪个好10Hive性能优化 1Hive性能问题排查的方式1.1Hive底层原理#xff1a;explain执行计划详解1.1.1 explain理论1.1.2 实践 2Hive性能调优的方式2.1. SQL语句优化1. union all2. distinct 2.2. 数据格式优化2.3. 小文件过多优化2.3.1解决hive小文件过多问题小文件产生的原因小文件… 10Hive性能优化 1Hive性能问题排查的方式1.1Hive底层原理explain执行计划详解1.1.1 explain理论1.1.2 实践 2Hive性能调优的方式2.1. SQL语句优化1. union all2. distinct 2.2. 数据格式优化2.3. 小文件过多优化2.3.1解决hive小文件过多问题小文件产生的原因小文件过多产生的影响怎么解决小文件过多1. 使用 hive 自带的 concatenate 命令自动合并小文件2. 调整参数减少Map数量3. 减少Reduce的数量4. 使用hadoop的archive将小文件归档如果是新集群没有历史遗留问题的话建议hive使用 orc 文件格式以及启用 lzo 压缩。这样小文件过多可以使用hive自带命令 concatenate 快速合并。 2.4. 并行执行优化2.5. JVM优化2.6. 推测执行优化 Hive作为大数据平台举足轻重的框架以其稳定性和简单易用性也成为当前构建企业级数据仓库时使用最多的框架之一。 但是如果我们只局限于会使用Hive而不考虑性能问题就难搭建出一个完美的数仓所以Hive性能调优是我们大数据从业者必须掌握的技能。 本节将给大家讲解Hive性能调优的一些方法及技巧。
1Hive性能问题排查的方式
当我们发现一条SQL语句执行时间过长或者不合理时我们就要考虑对SQL进行优化优化首先得进行问题排查那么我们可以通过哪些方式进行排查呢。
经常使用关系型数据库的同学可能知道关系型数据库的优化的诀窍-看执行计划。 如Oracle数据库它有多种类型的执行计划通过多种执行计划的配合使用可以看到根据统计信息推演的执行计划即Oracle推断出来的未真正运行的执行计划 还可以看到实际执行任务的执行计划 能够观察到从数据读取到最终呈现的主要过程和中间的量化数据。 可以说在Oracle开发领域掌握合适的环节选用不同的执行计划SQL调优就不是一件难事。
Hive中也有执行计划但是Hive的执行计划都是预测的这点不像Oracle和SQL Server有真实的计划可以看到每个阶段的处理数据、消耗的资源和处理的时间等量化数据。Hive提供的执行计划没有这些数据这意味着虽然Hive的使用者知道整个SQL的执行逻辑但是各阶段耗用的资源状况和整个SQL的执行瓶颈在哪里是不清楚的。 想要知道HiveSQL所有阶段的运行信息可以查看YARN提供的日志。查看日志的链接可以在每个作业执行后在控制台打印的信息中找到。如下图所示 Hive提供的执行计划目前可以查看的信息有以下几种 1.查看执行计划的基本信息即explain 2.查看执行计划的扩展信息即explain extended 3.查看SQL数据输入依赖的信息即explain dependency 4.查看SQL操作相关权限的信息即explain authorization 5.查看SQL的向量化描述信息即explain vectorization。
在查询语句的SQL前面加上关键字explain是查看执行计划的基本方法。 用explain打开的执行计划包含以下两部分 -作业的依赖关系图即STAGE DEPENDENCIES -每个作业的详细信息即STAGE PLANS。
总结Hive对SQL语句性能问题排查的方式 1.使用explain查看执行计划 2.查看YARN提供的日志。
1.1Hive底层原理explain执行计划详解
不懂hive中的explain说明hive还没入门学会explain能够给我们工作中使用hive带来极大的便利
1.1.1 explain理论
本节将介绍 explain 的用法及参数介绍
HIVE提供了EXPLAIN命令来展示一个查询的执行计划,这个执行计划对于我们了解底层原理hive 调优排查数据倾斜等很有帮助 使用语法如下
EXPLAIN [EXTENDED|CBO|AST|DEPENDENCY|AUTHORIZATION|LOCKS|VECTORIZATION|ANALYZE] queryexplain 后面可以跟以下可选参数注意这几个可选参数不是 hive 每个版本都支持的
1EXTENDED加上 extended 可以输出有关计划的额外信息。这通常是物理信息例如文件名。这些额外信息对我们用处不大
2CBO输出由Calcite优化器生成的计划。CBO 从 hive 4.0.0 版本开始支持
3AST输出查询的抽象语法树。AST 在hive 2.1.0 版本删除了存在bug转储AST可能会导致OOM错误将在4.0.0版本修复
4DEPENDENCYdependency在EXPLAIN语句中使用会产生有关计划中输入的额外信息。它显示了输入的各种属性
5AUTHORIZATION显示所有的实体需要被授权执行如果存在的查询和授权失败
6LOCKS这对于了解系统将获得哪些锁以运行指定的查询很有用。LOCKS 从 hive 3.2.0 开始支持
7VECTORIZATION将详细信息添加到EXPLAIN输出中以显示为什么未对Map和Reduce进行矢量化。从 Hive 2.3.0 开始支持
8ANALYZE用实际的行数注释计划。从 Hive 2.2.0 开始支持
在 hive cli 中输入以下命令(hive 2.3.7)
explain select sum(id) from test1;得到结果请逐行看完即使看不懂也要每行都看
STAGE DEPENDENCIES:Stage-1 is a root stageStage-0 depends on stages: Stage-1STAGE PLANS:Stage: Stage-1Map ReduceMap Operator Tree:TableScanalias: test1Statistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int)outputColumnNames: idStatistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEGroup By Operatoraggregations: sum(id)mode: hashoutputColumnNames: _col0Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorsort order:Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONEvalue expressions: _col0 (type: bigint)Reduce Operator Tree:Group By Operatoraggregations: sum(VALUE._col0)mode: mergepartialoutputColumnNames: _col0Statistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 1 Data size: 8 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.SequenceFileInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink看完以上内容有什么感受是不是感觉都看不懂不要着急下面将会详细讲解每个参数相信你学完下面的内容之后再看 explain 的查询结果将游刃有余。 一个HIVE查询被转换为一个由一个或多个stage组成的序列有向无环图DAG。这些stage可以是MapReduce stage也可以是负责元数据存储的stage也可以是负责文件系统的操作比如移动和重命名的stage。
我们将上述结果拆分看先从最外层开始包含两个大的部分 stage dependencies 各个stage之间的依赖性 stage plan 各个stage的执行计划
先看第一部分 stage dependencies 包含两个 stageStage-1 是根stage说明这是开始的stageStage-0 依赖 Stage-1Stage-1执行完成后执行Stage-0。
再看第二部分 stage plan里面有一个 Map Reduce一个MR的执行计划分为两个部分 Map Operator Tree MAP端的执行计划树 Reduce Operator Tree Reduce端的执行计划树
这两个执行计划树里面包含这条sql语句的 operator
map端第一个操作肯定是加载表所以就是 TableScan 表扫描操作常见的属性 alias 表名称Statistics 表统计信息包含表中数据条数数据大小等Select Operator 选取操作常见的属性
expressions需要的字段名称及字段类型outputColumnNames输出的列名称Statistics表统计信息包含表中数据条数数据大小等
Group By Operator分组聚合操作常见的属性
aggregations显示聚合函数信息mode聚合模式值有 hash随机聚合就是hash partitionpartial局部聚合final最终聚合keys分组的字段如果没有分组则没有此字段outputColumnNames聚合之后输出列名Statistics 表统计信息包含分组聚合之后的数据条数数据大小等
Reduce Output Operator输出到reduce操作常见属性
sort order值为空 不排序值为 正序排序值为 - 倒序排序值为 - 排序的列为两列第一列为正序第二列为倒序
5.Filter Operator过滤操作常见的属性
predicate过滤条件如sql语句中的where id1则此处显示(id 1)
Map Join Operatorjoin 操作常见的属性
condition mapjoin方式 如Inner Join 0 to 1 Left Outer Join0 to 2keys: join 的条件字段outputColumnNames join 完成之后输出的字段Statistics join 完成之后生成的数据条数大小等
File Output Operator文件输出操作常见的属性
compressed是否压缩table表的信息包含输入输出文件格式化方式序列化方式等
Fetch Operator 客户端获取数据操作常见的属性
limit值为 -1 表示不限制条数其他值为限制的条数
好学到这里再翻到上面 explain 的查询结果是不是感觉基本都能看懂了。
1.1.2 实践
1. join 语句会过滤 null 的值吗 现在我们在hive cli 输入以下查询计划语句
select a.id,b.user_name from test1 a join test2 b on a.idb.id;问上面这条 join 语句会过滤 id 为 null 的值吗
执行下面语句
explain select a.id,b.user_name from test1 a join test2 b on a.idb.id;我们来看结果 (为了适应页面展示仅截取了部分输出信息)
TableScanalias: aStatistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: id is not null (type: boolean)Statistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int)outputColumnNames: _col0Statistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEHashTable Sink Operatorkeys:0 _col0 (type: int)1 _col0 (type: int)...从上述结果可以看到 predicate: id is not null 这样一行说明 join 时会自动过滤掉关联字段为 null 值的情况但 left join 或 full join 是不会自动过滤的大家可以自行尝试下。 2. group by 分组语句会进行排序吗 看下面这条sql
select id,max(user_name) from test1 group by id;问group by 分组语句会进行排序吗
直接来看 explain 之后结果 (为了适应页面展示仅截取了部分输出信息) TableScanalias: test1Statistics: Num rows: 9 Data size: 108 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int), user_name (type: string)outputColumnNames: id, user_nameStatistics: Num rows: 9 Data size: 108 Basic stats: COMPLETE Column stats: NONEGroup By Operatoraggregations: max(user_name)keys: id (type: int)mode: hashoutputColumnNames: _col0, _col1Statistics: Num rows: 9 Data size: 108 Basic stats: COMPLETE Column stats: NONEReduce Output Operatorkey expressions: _col0 (type: int)sort order: Map-reduce partition columns: _col0 (type: int)Statistics: Num rows: 9 Data size: 108 Basic stats: COMPLETE Column stats: NONEvalue expressions: _col1 (type: string)...我们看 Group By Operator里面有 keys: id (type: int) 说明按照 id 进行分组的再往下看还有 sort order: 说明是按照 id 字段进行正序排序的。 3. 哪条sql执行效率高呢
2Hive性能调优的方式
为什么都说性能优化这项工作是比较难的因为一项技术的优化必然是一项综合性的工作它是多门技术的结合。我们如果只局限于一种技术那么肯定做不好优化的。 下面将从多个完全不同的角度来介绍Hive优化的多样性我们先来一起感受下。 观察两条sql语句
SELECTa.id,b.user_name
FROMtest1 a
JOIN test2 b ON a.id b.id
WHEREa.id 2;SELECTa.id,b.user_name
FROM(SELECT * FROM test1 WHERE id 2) a
JOIN test2 b ON a.id b.id;这两条sql语句输出的结果是一样的但是哪条sql执行效率高呢 有人说第一条sql执行效率高因为第二条sql有子查询子查询会影响性能 有人说第二条sql执行效率高因为先过滤之后在进行join时的条数减少了所以执行效率就高了
到底哪条sql效率高呢我们直接在sql语句前面加上 explain看下执行计划不就知道了嘛
在第一条sql语句前加上 explain得到如下结果
hive (default) explain select a.id,b.user_name from test1 a join test2 b on a.idb.id where a.id 2;
OK
Explain
STAGE DEPENDENCIES:Stage-4 is a root stageStage-3 depends on stages: Stage-4Stage-0 depends on stages: Stage-3STAGE PLANS:Stage: Stage-4Map Reduce Local WorkAlias - Map Local Tables:$hdt$_0:aFetch Operatorlimit: -1Alias - Map Local Operator Tree:$hdt$_0:aTableScanalias: aStatistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (id 2) (type: boolean)Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int)outputColumnNames: _col0Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONEHashTable Sink Operatorkeys:0 _col0 (type: int)1 _col0 (type: int)Stage: Stage-3Map ReduceMap Operator Tree:TableScanalias: bStatistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (id 2) (type: boolean)Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int), user_name (type: string)outputColumnNames: _col0, _col1Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONEMap Join Operatorcondition map:Inner Join 0 to 1keys:0 _col0 (type: int)1 _col0 (type: int)outputColumnNames: _col0, _col2Statistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: _col0 (type: int), _col2 (type: string)outputColumnNames: _col0, _col1Statistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.SequenceFileInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeLocal Work:Map Reduce Local WorkStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink在第二条sql语句前加上 explain得到如下结果
hive (default) explain select a.id,b.user_name from(select * from test1 where id2 ) a join test2 b on a.idb.id;
OK
Explain
STAGE DEPENDENCIES:Stage-4 is a root stageStage-3 depends on stages: Stage-4Stage-0 depends on stages: Stage-3STAGE PLANS:Stage: Stage-4Map Reduce Local WorkAlias - Map Local Tables:$hdt$_0:test1Fetch Operatorlimit: -1Alias - Map Local Operator Tree:$hdt$_0:test1TableScanalias: test1Statistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (id 2) (type: boolean)Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int)outputColumnNames: _col0Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONEHashTable Sink Operatorkeys:0 _col0 (type: int)1 _col0 (type: int)Stage: Stage-3Map ReduceMap Operator Tree:TableScanalias: bStatistics: Num rows: 6 Data size: 75 Basic stats: COMPLETE Column stats: NONEFilter Operatorpredicate: (id 2) (type: boolean)Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: id (type: int), user_name (type: string)outputColumnNames: _col0, _col1Statistics: Num rows: 2 Data size: 25 Basic stats: COMPLETE Column stats: NONEMap Join Operatorcondition map:Inner Join 0 to 1keys:0 _col0 (type: int)1 _col0 (type: int)outputColumnNames: _col0, _col2Statistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONESelect Operatorexpressions: _col0 (type: int), _col2 (type: string)outputColumnNames: _col0, _col1Statistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONEFile Output Operatorcompressed: falseStatistics: Num rows: 2 Data size: 27 Basic stats: COMPLETE Column stats: NONEtable:input format: org.apache.hadoop.mapred.SequenceFileInputFormatoutput format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormatserde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDeLocal Work:Map Reduce Local WorkStage: Stage-0Fetch Operatorlimit: -1Processor Tree:ListSink大家有什么发现除了表别名不一样其他的执行计划完全一样都是先进行 where 条件过滤在进行 join 条件关联。说明 hive 底层会自动帮我们进行优化所以这两条sql语句执行效率是一样的。 最后 以上仅列举了3个我们生产中既熟悉又有点迷糊的例子explain 还有很多其他的用途如查看stage的依赖情况、排查数据倾斜、hive 调优等小伙伴们可以自行尝试。
2.1. SQL语句优化
SQL语句优化涉及到的内容太多因篇幅有限不能一一介绍到所以就拿几个典型举例让大家学到这种思想以后遇到类似调优问题可以往这几个方面多思考下。
1. union all
insert into table stu partition(tp)
select s_age,max(s_birth) stat,max tp
from stu_ori
group by s_ageunion allinsert into table stu partition(tp)
select s_age,min(s_birth) stat,min tp
from stu_ori
group by s_age;我们简单分析上面的SQl语句就是将每个年龄的最大和最小的生日获取出来放到同一张表中union all 前后的两个语句都是对同一张表按照s_age进行分组然后分别取最大值和最小值。对同一张表相同的字段进行两次分组这造成了极大浪费我们能不能改造下呢当然是可以的为大家介绍一个语法 from … insert into … 这个语法将from前置作用就是使用一张表可以进行多次插入操作
–开启动态分区
set hive.exec.dynamic.partitiontrue;
set hive.exec.dynamic.partition.modenonstrict; from stu_ori insert into table stu partition(tp)
select s_age,max(s_birth) stat,max tp
group by s_ageinsert into table stu partition(tp)
select s_age,min(s_birth) stat,min tp
group by s_age;上面的SQL就可以对stu_ori表的s_age字段分组一次而进行两次不同的插入操作。 这个例子告诉我们一定要多了解SQL语句如果我们不知道这种语法一定不会想到这种方式的。
2. distinct
先看一个SQL去重计数
select count(1)
from( select s_age from stu group by s_age
) b;这是简单统计年龄的枚举值个数为什么不用distinct
select count(distinct s_age)
from stu;有人说因为在数据量特别大的情况下使用第一种方式能够有效避免Reduce端的数据倾斜但是事实如此吗 我们先不管数据量特别大这个问题就当前的业务和环境下使用distinct一定会比上面那种子查询的方式效率高。原因有以下几点 1.上面进行去重的字段是年龄字段要知道年龄的枚举值是非常有限的就算计算1岁到100岁之间的年龄s_age的最大枚举值才是100如果转化成MapReduce来解释的话在Map阶段每个Map会对s_age去重。由于s_age枚举值有限因而每个Map得到的s_age也有限最终得到reduce的数据量也就是map数量*s_age枚举值的个数。 2.distinct的命令会在内存中构建一个hashtable查找去重的时间复杂度是O(1)group by在不同版本间变动比较大有的版本会用构建hashtable的形式去重有的版本会通过排序的方式 排序最优时间复杂度无法到O(1)。另外第一种方式(group by)去重会转化为两个任务会消耗更多的磁盘网络I/O资源。 3.最新的Hive 3.0中新增了 count(distinct ) 优化通过配置 hive.optimize.countdistinct即使真的出现数据倾斜也可以自动优化自动改变SQL执行的逻辑。 4.第二种方式(distinct)比第一种方式(group by)代码简洁表达的意思简单明了如果没有特殊的问题代码简洁就是优 这个例子告诉我们有时候我们不要过度优化调优讲究适时调优过早进行调优有可能做的是无用功甚至产生负效应在调优上投入的工作成本和回报不成正比。调优需要遵循一定的原则。
2.2. 数据格式优化
Hive提供了多种数据存储组织格式不同格式对程序的运行效率也会有极大的影响。 Hive提供的格式有TEXT、SequenceFile、RCFile、ORC和Parquet等。 SequenceFile是一个二进制key/value对结构的平面文件在早期的Hadoop平台上被广泛用于MapReduce输出/输出格式以及作为数据存储格式。 Parquet是一种列式数据存储格式可以兼容多种计算引擎如MapRedcue和Spark等对多层嵌套的数据结构提供了良好的性能支持是目前Hive生产环境中数据存储的主流选择之一。 ORC优化是对RCFile的一种优化它提供了一种高效的方式来存储Hive数据同时也能够提高Hive的读取、写入和处理数据的性能能够兼容多种计算引擎。事实上在实际的生产环境中ORC已经成为了Hive在数据存储上的主流选择之一。 我们使用同样数据及SQL语句只是数据存储格式不同得到如下执行时长 注CPU时间表示运行程序所占用服务器CPU资源的时间。 用户等待耗时记录的是用户从提交作业到返回结果期间用户等待的所有时间。 查询TextFile类型的数据表耗时33分钟 查询ORC类型的表耗时1分52秒时间得以极大缩短可见不同的数据存储格式也能给HiveSQL性能带来极大的影响。
2.3. 小文件过多优化
小文件如果过多对 hive 来说在进行查询时每个小文件都会当成一个块启动一个Map任务来完成而一个Map任务启动和初始化的时间远远大于逻辑处理的时间就会造成很大的资源浪费。而且同时可执行的Map数量是受限的。 所以我们有必要对小文件过多进行优化关于小文件过多的解决的办法如下
2.3.1解决hive小文件过多问题
小文件产生的原因
hive 中的小文件肯定是向 hive 表中导入数据时产生所以先看下向 hive 中导入数据的几种方式
1.直接向表中插入数据
insert into table A values (1,zhangsan,88),(2,lisi,61);这种方式每次插入时都会产生一个文件多次插入少量数据就会出现多个小文件但是这种方式生产环境很少使用可以说基本没有使用的
2.通过load方式加载数据
load data local inpath /export/score.csv overwrite into table A -- 导入文件load data local inpath /export/score overwrite into table A -- 导入文件夹使用 load 方式可以导入文件或文件夹当导入一个文件时hive表就有一个文件当导入文件夹时hive表的文件数量为文件夹下所有文件的数量
3.通过查询方式加载数据
insert overwrite table A select s_id,c_name,s_score from B;这种方式是生产环境中常用的也是最容易产生小文件的方式
insert 导入数据时会启动 MR 任务MR中 reduce 有多少个就输出多少个文件
所以 文件数量ReduceTask数量*分区数
也有很多简单任务没有reduce只有map阶段则
文件数量MapTask数量*分区数
每执行一次 insert 时hive中至少产生一个文件因为 insert 导入时至少会有一个MapTask。 像有的业务需要每10分钟就要把数据同步到 hive 中这样产生的文件就会很多。
小文件过多产生的影响
首先对底层存储HDFS来说HDFS本身就不适合存储大量小文件小文件过多会导致namenode元数据特别大, 占用太多内存严重影响HDFS的性能
对 hive 来说在进行查询时每个小文件都会当成一个块启动一个Map任务来完成而一个Map任务启动和初始化的时间远远大于逻辑处理的时间就会造成很大的资源浪费。而且同时可执行的Map数量是受限的。
怎么解决小文件过多
1. 使用 hive 自带的 concatenate 命令自动合并小文件
使用方法
#对于非分区表
alter table A concatenate;#对于分区表
alter table B partition(day20201224) concatenate;举例
#向 A 表中插入数据
hive (default) insert into table A values (1,aa,67),(2,bb,87);
hive (default) insert into table A values (3,cc,67),(4,dd,87);
hive (default) insert into table A values (5,ee,67),(6,ff,87);#执行以上三条语句则A表下就会有三个小文件,在hive命令行执行如下语句
#查看A表下文件数量
hive (default) dfs -ls /user/hive/warehouse/A;
Found 3 items
-rwxr-xr-x 3 root supergroup 378 2020-12-24 14:46 /user/hive/warehouse/A/000000_0
-rwxr-xr-x 3 root supergroup 378 2020-12-24 14:47 /user/hive/warehouse/A/000000_0_copy_1
-rwxr-xr-x 3 root supergroup 378 2020-12-24 14:48 /user/hive/warehouse/A/000000_0_copy_2#可以看到有三个小文件然后使用 concatenate 进行合并
hive (default) alter table A concatenate;#再次查看A表下文件数量
hive (default) dfs -ls /user/hive/warehouse/A;
Found 1 items
-rwxr-xr-x 3 root supergroup 778 2020-12-24 14:59 /user/hive/warehouse/A/000000_0#已合并成一个文件注意 1、concatenate 命令只支持 RCFILE 和 ORC 文件类型。 2、使用concatenate命令合并小文件时不能指定合并后的文件数量但可以多次执行该命令。 3、当多次使用concatenate后文件数量不在变化这个跟参数 mapreduce.input.fileinputformat.split.minsize256mb 的设置有关可设定每个文件的最小size。
2. 调整参数减少Map数量
设置map输入合并小文件的相关参数
#执行Map前进行小文件合并
#CombineHiveInputFormat底层是 Hadoop的 CombineFileInputFormat 方法
#此方法是在mapper中将多个文件合成一个split作为输入
set hive.input.formatorg.apache.hadoop.hive.ql.io.CombineHiveInputFormat; -- 默认#每个Map最大输入大小(这个值决定了合并后文件的数量)
set mapred.max.split.size256000000; -- 256M#一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并)
set mapred.min.split.size.per.node100000000; -- 100M#一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并)
set mapred.min.split.size.per.rack100000000; -- 100M设置map输出和reduce输出进行合并的相关参数:
#设置map端输出进行合并默认为true
set hive.merge.mapfiles true;#设置reduce端输出进行合并默认为false
set hive.merge.mapredfiles true;#设置合并文件的大小
set hive.merge.size.per.task 256*1000*1000; -- 256M#当输出文件的平均大小小于该值时启动一个独立的MapReduce任务进行文件merge
set hive.merge.smallfiles.avgsize16000000; -- 16M 启用压缩
# hive的查询结果输出是否进行压缩
set hive.exec.compress.outputtrue;# MapReduce Job的结果输出是否使用压缩
set mapreduce.output.fileoutputformat.compresstrue;3. 减少Reduce的数量
#reduce 的个数决定了输出的文件的个数所以可以调整reduce的个数控制hive表的文件数量
#hive中的分区函数 distribute by 正好是控制MR中partition分区的
#然后通过设置reduce的数量结合分区函数让数据均衡的进入每个reduce即可。#设置reduce的数量有两种方式第一种是直接设置reduce个数
set mapreduce.job.reduces10;#第二种是设置每个reduce的大小Hive会根据数据总大小猜测确定一个reduce个数
set hive.exec.reducers.bytes.per.reducer5120000000; -- 默认是1G设置为5G#执行以下语句将数据均衡的分配到reduce中
set mapreduce.job.reduces10;
insert overwrite table A partition(dt)
select * from B
distribute by rand();解释如设置reduce数量为10则使用 rand() 随机生成一个数 x % 10
这样数据就会随机进入 reduce 中防止出现有的文件过大或过小4. 使用hadoop的archive将小文件归档
Hadoop Archive简称HAR是一个高效地将小文件放入HDFS块中的文件存档工具它能够将多个小文件打包成一个HAR文件这样在减少namenode内存使用的同时仍然允许对文件进行透明的访问
#用来控制归档是否可用
set hive.archive.enabledtrue;
#通知Hive在创建归档时是否可以设置父目录
set hive.archive.har.parentdir.settabletrue;
#控制需要归档文件的大小
set har.partfile.size1099511627776;#使用以下命令进行归档
ALTER TABLE A ARCHIVE PARTITION(dt2020-12-24, hr12);#对已归档的分区恢复为原文件
ALTER TABLE A UNARCHIVE PARTITION(dt2020-12-24, hr12);注意: 归档的分区可以查看不能 insert overwrite必须先 unarchive
如果是新集群没有历史遗留问题的话建议hive使用 orc 文件格式以及启用 lzo 压缩。这样小文件过多可以使用hive自带命令 concatenate 快速合并。
2.4. 并行执行优化
Hive会将一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。或者Hive执行过程中可能需要的其他阶段。默认情况下Hive一次只会执行一个阶段。不过某个特定的job可能包含众多的阶段而这些阶段可能并非完全互相依赖的也就是说有些阶段是可以并行执行的这样可能使得整个job的执行时间缩短。如果有更多的阶段可以并行执行那么job可能就越快完成。 通过设置参数hive.exec.parallel值为true就可以开启并发执行。在共享集群中需要注意下如果job中并行阶段增多那么集群利用率就会增加。
set hive.exec.paralleltrue; //打开任务并行执行
set hive.exec.parallel.thread.number16; //同一个sql允许最大并行度默认为8。当然得是在系统资源比较空闲的时候才有优势否则没资源并行也起不来。
2.5. JVM优化
JVM重用是Hadoop调优参数的内容其对Hive的性能具有非常大的影响特别是对于很难避免小文件的场景或task特别多的场景这类场景大多数执行时间都很短。 Hadoop的默认配置通常是使用派生JVM来执行map和Reduce任务的。这时JVM的启动过程可能会造成相当大的开销尤其是执行的job包含有成百上千task任务的情况。JVM重用可以使得JVM实例在同一个job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件中进行配置。通常在10-20之间具体多少需要根据具体业务场景测试得出。
propertynamemapreduce.job.jvm.numtasks/namevalue10/valuedescriptionHow many tasks to run per jvm. If set to -1, there isno limit. /description
/property我们也可以在hive中设置
set mapred.job.reuse.jvm.num.tasks10; //这个设置来设置我们的jvm重用这个功能的缺点是开启JVM重用将一直占用使用到的task插槽以便进行重用直到任务完成后才能释放。如果某个“不平衡的”job中有某几个reduce task执行的时间要比其他Reduce task消耗的时间多的多的话那么保留的插槽就会一直空闲着却无法被其他的job使用直到所有的task都结束了才会释放。
2.6. 推测执行优化
在分布式集群环境下因为程序Bug包括Hadoop本身的bug负载不均衡或者资源分布不均等原因会造成同一个作业的多个任务之间运行速度不一致有些任务的运行速度可能明显慢于其他任务比如一个作业的某个任务进度只有50%而其他所有任务已经运行完毕则这些任务会拖慢作业的整体执行进度。为了避免这种情况发生Hadoop采用了推测执行Speculative Execution机制它根据一定的法则推测出“拖后腿”的任务并为这样的任务启动一个备份任务让该任务与原始任务同时处理同一份数据并最终选用最先成功运行完成任务的计算结果作为最终结果。 设置开启推测执行参数Hadoop的mapred-site.xml文件中进行配置
propertynamemapreduce.map.speculative/namevaluetrue/valuedescriptionIf true, then multiple instances of some map tasks may be executed in parallel./description
/propertypropertynamemapreduce.reduce.speculative/namevaluetrue/valuedescriptionIf true, then multiple instances of some reduce tasks may be executed in parallel./description
/propertyhive本身也提供了配置项来控制reduce-side的推测执行:
set hive.mapred.reduce.tasks.speculative.executiontrue关于调优这些推测执行变量还很难给一个具体的建议。如果用户对于运行时的偏差非常敏感的话那么可以将这些功能关闭掉。如果用户因为输入数据量很大而需要执行长时间的map或者Reduce task的话那么启动推测执行造成的浪费是非常巨大大。
最后 代码优化原则 -理透需求原则这是优化的根本 -把握数据全链路原则这是优化的脉络 -坚持代码的简洁原则这让优化更加简单 -没有瓶颈时谈论优化这是自寻烦恼。