hive调优
hive命令和参数配置
1.hive数据压缩
==Hive底层是运行MapReduce,所以Hive支持什么压缩格式本质上取决于MapReduce。==
压缩对比
开启压缩
-- 创建数据库
create database hive05;
-- 使用库
use hive05;
-- 开启压缩(map阶段或者reduce阶段)
--开启hive支持中间结果的压缩方案
set hive.exec.compress.intermediate; -- 查看默认
set hive.exec.compress.intermediate=true ;
--开启hive支持最终结果压缩
set hive.exec.compress.output; -- 查看默认
set hive.exec.compress.output=true;
--开启MR的map端压缩操作
set mapreduce.map.output.compress; -- 查看默认
set mapreduce.map.output.compress=true;
--设置mapper端压缩的方案
set mapreduce.map.output.compress.codec; -- 查看默认
set mapreduce.map.output.compress.codec= org.apache.hadoop.io.compress.SnappyCodec;
-- 开启MR的reduce端的压缩方案
set mapreduce.output.fileoutputformat.compress; -- 查看默认
set mapreduce.output.fileoutputformat.compress=true;
-- 设置reduce端压缩的方案
set mapreduce.output.fileoutputformat.compress.codec; -- 查看默认
set mapreduce.output.fileoutputformat.compress.codec = org.apache.hadoop.io.compress.SnappyCodec;
--设置reduce的压缩类型
set mapreduce.output.fileoutputformat.compress.type; -- 查看默认
set mapreduce.output.fileoutputformat.compress.type=BLOCK;
2.hive数据存储[练习]
行列存储原理
存储压缩比
-- 存储格式应用对比
-- 演示textfile行存储格式: 18.1 m
create table log_text (
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE ; -- TEXTFILE当前默认的,可以省略
-- 查询数据
select * from log_text;
-- 演示orc列存储(默认zlib): 2.78 m
create table log_orc(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc ;-- 默认内置一种压缩算法:ZLIB
-- 加载数据(先上传数据文件到根目录)
insert into table log_orc select * from log_text;
-- 查询数据
select * from log_orc;
-- [重点orc配合snappy]
-- 演示orc列存储(指定snappy): 3.75 m
create table log_orc_snappy(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS orc tblproperties ("orc.compress"="SNAPPY"); -- 配合SNAPPY压缩
-- 加载数据(先上传数据文件到根目录)
insert into table log_orc_snappy select * from log_text;
-- 查询数据
select * from log_orc_snappy;
/*ORC文件格式的数据, 默认内置一种压缩算法:ZLIB , 在实际生产中一般会将ORC压缩算法替换为 snappy
格式为: STORED AS orc tblproperties ("orc.compress"="SNAPPY") */
-- 演示parquet压缩存储:13.09 m
create table log_parquet(
track_time string,
url string,
session_id string,
referer string,
ip string,
end_user_id string,
city_id string
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t'
STORED AS PARQUET ;
-- 加载数据(先上传数据文件到根目录)
insert into table log_parquet select * from log_text;
-- 查询数据
select * from log_parquet;
拓展dfs -du -h
-- 查看hdfs文件大小除了去页面查看,还可以通过命令
dfs -du -h '/user/hive/warehouse/hive05.db/log_text/log.data' ;
dfs -du -h '/user/hive/warehouse/hive05.db/log_orc/000000_0' ;
dfs -du -h '/user/hive/warehouse/hive05.db/log_orc_snappy/000000_0' ;
dfs -du -h '/user/hive/warehouse/hive05.db/log_parquet/000000_0' ;
3. fetch抓取
==核心点: 在执行SQL, 能不走MR, 尽量不走MR==
回想, 在之前执行什么样查询的SQL的时候,没有走MR呢?
而这些操作, 没有走MR原因, 就是hive默认以及开启本地抓取的策略方案:
示例:
-- 默认是more,底层自动调优
set hive.fetch.task.conversion; -- 默认结果是more
set hive.fetch.task.conversion = more;
select * from log_text; -- 不走mr
select url from log_text;-- 不走mr
select url from log_text limit 3;-- 不走mr
select url from log_text where city_id = -1;-- 不走mr
-- 可以体验下minimal模式
set hive.fetch.task.conversion = minimal;
select * from log_text;-- 不走mr
select url from log_text;-- 不走mr
select url from log_text limit 3;-- 不走mr
select url from log_text where city_id = -1;-- 走mr
-- 还可以体验下none模式
set hive.fetch.task.conversion = none;
select * from log_text;-- 走mr
select url from log_text;-- 走mr
select url from log_text limit 3;-- 走mr
select url from log_text where city_id = -1;-- 走mr
4. 本地模式
==核心点:让MR能走本地模式, 尽量走本地MR(大白话: 小活能自己干就不要麻烦别人)==
示例:
-- 4.开启本地mr(默认false,如果小数据任务进行调优开启,小任务能自己干就自己干)
set hive.exec.mode.local.auto; -- 默认关闭
set hive.exec.mode.local.auto=false; -- 手动关闭
set hive.exec.mode.local.auto=true; -- 手动开启
--设置local mr的最大输入数据量,当输入数据量小于这个值时采用local mr的方式,默认为134217728,即128M
set hive.exec.mode.local.auto.inputbytes.max;-- 查看
set hive.exec.mode.local.auto.inputbytes.max=134217728;
--设置local mr的最大输入文件个数,当输入文件个数小于这个值时采用local mr的方式,默认为4
set hive.exec.mode.local.auto.input.files.max;-- 查看
set hive.exec.mode.local.auto.input.files.max=4;
-- 执行sql语句
-- 没有开启本地执行24秒,开启后1.5秒
select * from log_text order by city_id desc;
-- 注意: 有的同学开启本地模式后执行上述sql语句,会报code 2...错误
-- 错误:[08S01][2] Error while processing statement: FAILED: Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.mr.MapRedTask
-- 如何解决? /export/server/hive/hive-env.sh 修改 export HADOOP_HEAPSIZE=2048
-- 注意: 修改完后需要重启hive服务
5. join的优化操作
思考: 在通过hive执行多表查询的SQL, 最终hive翻译的MR,是如何完成join的工作的呢?
默认的join行为, 基于reduce端的join工作
思考, 请问上述join存在哪些问题?
==那么如何解决reduce端join遇到问题? 可以通过底层map 端 join实现,还可以sql语句join之前提前过滤数据或者转换数据实现==
-
1) 大表和小表进行join:
-
解决方案: map join
-
如何开启这种操作呢?
set hive.auto.convert.join = true; -- 默认为true 开启mapJoin支持 set hive.mapjoin.smalltable.filesize= 25000000; 设置 小表的最大的数据量 23.84m
-
在执行SQL, 应该将小表放置前面呢, 还是大表放置在前面呢,还是都可以呢 ?
-
-
3) 大表和大表join
-
解决方案:
-
6. 列裁剪
==Hive在读数据的时候,可以只读取查询中所需要用到的列,而忽略其他列==
例如:
如何配置呢?
-- 6.列裁剪(只读取sql语句需要的字段,节省读取开销,提升效率)
set hive.optimize.cp=true; -- 默认就是true (在hive 2.x中无需在配置了, 直接为固定值: true)
7. 分区裁剪
==执行查询SQL的时候, 能在join之前提前进行条件过滤的操作, 一定要提前过滤, 不要在join后进行过滤操作==
如果操作的表是一张分区表, 那么建议一定要带上分区字段, 以减少扫描的数据量, 从而提升效率,
例如:
select * from A join B where A.id=xxx;
优化后:
select * from (select * from A where id= xxx) A join B;
如何配置呢?
-- 7.分区裁剪
set hive.optimize.pruner=true; --默认为就是true (在hive 2.x中无需在配置了, 直接为固定值: true)
8. group by 操作
执行分组操作, 翻译后的MR, 分组的字段就是k2的字段, 按照k2进行分组操作, 将相同value合并在同一个集合中, 既然分组的字段就是MR的k2, 那么分区也会按照分组字段进行分区操作, 如果某个组下数据非常的多, 可能出现出现什么问题呢?
如何在hive中配置:
方案一:
--(1)是否在Map端进行聚合,默认为True
set hive.map.aggr = true;
--(2)在Map端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = 100000;
方案二: 官方称为 负载均衡
--(3)有数据倾斜的时候进行负载均衡(默认是false)
set hive.groupby.skewindata = true;
9. count(distinct)
说明 : count(distinct) 在数据量比较大的情况下, 效率并不高
思考: 你知道是为什么吗?
-- count(distinct)优化
set hive.optimize.countdistinct; -- 默认就是true
set hive.optimize.countdistinct = true;
/*
SELECT count(DISTINCT id) FROM 大表;
结果:
SELECT count(id) FROM (SELECT id FROM 大表 GROUP BY id) a;
*/
select count(distinct devicetype) from device1;
select count(devicetype) from (select devicetype from device1 group by devicetype) a;
-- 注意: 小表拆分两个mr反而效率低,以后大表的时候才会真正提升效率
10. 笛卡尔积
什么是笛卡尔积呢? 在进行join的时候, 两个表乘积之后结果就是笛卡尔积的结果
比如: 一个表有5条, 一个表有3条数据, 笛卡尔积结果就有15条数据 , 笛卡尔积中有大量数据都是无用数据
什么时候会产生笛卡尔积呢? 在多表join的时候, 关联条件缺少或者使用错误的关联条件以及将关联条件放置在where中都会导致笛卡尔积
在实际使用中, 建议:
11. 动态分区[练习]
需求: 请将下面的一个分区表数据, 拷贝到另一个分区表, 保证对应区数据放置到另一个表的对应区下
如何配置呢?
作用: 帮助一次性灌入多个分区的数据
参数:
set hive.exec.dynamic.partition.mode=nonstrict; -- 开启非严格模式 默认为 strict(严格模式)
set hive.exec.dynamic.partition=true; -- 开启动态分区支持, 默认就是true
可选的参数:
set hive.exec.max.dynamic.partitions=1000; -- 在所有执行MR的节点上,最大一共可以创建多少个动态分区。
set hive.exec.max.dynamic.partitions.pernode=100; -- 每个执行MR的节点上,最大可以创建多少个动态分区
set hive.exec.max.created.files=100000; -- 整个MR Job中,最大可以创建多少个HDFS文件
示例:
-- 回顾快速创建表
-- 1.根据score.txt数据以及格式创建表
create table score_part(
name string,
subject string,
score int
)partitioned by (year string)
row format delimited fields terminated by '\t'
;
-- 2.上传score.txt到hdfs中
-- 注意: 分区表需要把文件上传到分区目录中,但是一开始没有目录,所以文件上传到任意目录后,等有了分区目录再使用load移动即可
-- 需要使用load方式生成分区目录并且插入数据
load data inpath '/score.txt' into table score_part partition (year='2022');
-- 3.hive根据元数据和分区目录中业务数据映射成表
select * from score_part;
-- 方式1: 先复制表结构再插入数据
-- 复制表结构,原来的是分区表,复制后也是分区表
create table score_part1 like score_part;
-- 不指定分区字段进行动态分区
insert into score_part1 select * from score_part;
-- 方式2: 一步到位
-- 弊端: 但是作为普通表使用了
create table score_part2 as select * from score_part;
-- 方式3: 动态分区
-- 关闭严格模式
set hive.exec.dynamic.partition.mode=nonstrict;
-- 复制表结构,原来的是分区表,复制后也是分区表
create table score_part3 like score_part;
-- 指定分区字段进行动态分区(必须是非严格模式)
insert into score_part3 partition (year) select * from score_part;
12. 如何调整map和reduce的数量
-
如何调整mapTask数量:
小文件场景:当input的文件都很小,把小文件进行合并归档,减少map数, 设置map数量:
-- 每个Map最大输入大小(这个值决定了合并后文件的数量) set mapred.max.split.size=256000000; -- 一个节点上split的至少的大小(这个值决定了多个DataNode上的文件是否需要合并) set mapred.min.split.size.per.node=1; -- 一个交换机下split的至少的大小(这个值决定了多个交换机上的文件是否需要合并) set mapred.min.split.size.per.rack=1; -- 执行Map前进行小文件合并默认CombineHiveInputFormat set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
大文件场景:当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。
-
如何reduce的数量:
-- 查看reduces数量 -- 该值默认为-1,由hive自己根据任务情况进行判断。 set mapred.reduce.tasks; set mapreduce.job.reduces; -- (1)每个Reduce处理的数据量默认是256MB左右 set hive.exec.reducers.bytes.per.reducer=256000000; -- (2)每个任务最大的reduce数,默认为1009; set hive.exec.reducers.max=1009;
13.并行执行
在执行一个SQL语句的时候, SQL会被翻译为MR, 一个SQL有可能被翻译成多个MR, 那么在多个MR之间, 有些MR之间可能不存在任何的关联, 此时可以设置让这些没有关联的MR 并行执行, 从而提升效率 , 默认是 一个一个来
如何配置:
set hive.exec.parallel=false; --打开任务并行执行,默认关闭
set hive.exec.parallel.thread.number=8; --同一个sql允许最大并行度,默认为8。
前提: 服务器必须有资源, 如果没有 即使支持并行, 也没有任何作用
案例:
select * from A ....
union all
select * from B ...;
例如:
select from (select * from A group by ...) tmp1 join (select * from B group by xxx) on ...
14. 严格模式
hive提供一种严格模式, 主要目的, 是为了限制一些 效率极低的SQL 放置其执行时间过长, 影响其他的操作
如何配置:
set hive.mapred.mode = strict; --开启严格模式
set hive.mapred.mode = nostrict; --开启非严格模式 最新默认
15. JVM 重用
此操作, 在hive2.x已经不需要配置了, 默认支持
16. 推测执行
17.执行计划explain
Hadoop进阶
HDFS
块和副本
图解:
三大机制
写入数据原理[面试]
读取数据原理[面试]
edits和fsimage文件
内存/文件元数据
图解
查看历史编辑文件
[root@node1 current]# cd /export/data/hadoop/dfs/name/current
[root@node1 current]# hdfs oev -i edits_0000000000000033404-0000000000000033405 -o 405_edit.xml
[root@node1 current]# cat 405_edit.xml
查看镜像文件
[root@node1 current]# cd /export/data/hadoop/dfs/name/current
[root@node1 current]# hdfs oiv -i fsimage_0000000000000033405 -p XML -o 405_fsimage.xml
[root@node1 current]# cat 405_fsimage.xml
元数据存储的原理[面试]
安全模式
#查看安全模式状态:
[root@node1 /]# hdfs dfsadmin -safemode get
Safe mode is OFF
#开启安全模式:
[root@node1 /]# hdfs dfsadmin -safemode enter
Safe mode is ON
#退出安全模式:
[root@node1 /]# hdfs dfsadmin -safemode leave
Safe mode is OFF
归档机制
[root@node1 /]# hadoop archive -archiveName test.har -p /binzi /
...
[root@node1 /]# hdfs dfs -ls /test1.har
Found 4 items
-rw-r--r-- 3 root supergroup 0 2022-12-27 15:56 /test.har/_SUCCESS
-rw-r--r-- 3 root supergroup 254 2022-12-27 15:56 /test.har/_index
-rw-r--r-- 3 root supergroup 23 2022-12-27 15:56 /test.har/_masterindex
-rw-r--r-- 3 root supergroup 47 2022-12-27 15:56 /test.har/part-0
[root@node1 /]# hdfs dfs -cat /test1.har/part-0
...
[root@node1 /]# hdfs dfs -ls har:///test.har
Found 3 items
-rw-r--r-- 3 root supergroup 15 2022-12-27 15:55 har:///test.har/1.txt
-rw-r--r-- 3 root supergroup 16 2022-12-27 15:55 har:///test.har/2.txt
-rw-r--r-- 3 root supergroup 16 2022-12-27 15:55 har:///test.har/3.txt
[root@node1 /]# hdfs dfs -cat har:///test.har/1.txt
...
[root@node1 /]# hdfs dfs -cat har:///test.har/2.txt
...
[root@node1 /]# hdfs dfs -cat har:///test.har/3.txt
...
垃圾桶机制
# 没有开启垃圾桶效果
[root@node1 hadoop]# hdfs dfs -rm /binzi/hello.txt
Deleted /binzi/hello.txt
# 开启垃圾桶
[root@node1 ~]#cd /export/server/hadoop-3.3.0/etc/hadoop
[root@node1 hadoop]# vim core-site.xml
# 注意: 放到<configuration>内容</configuration>中间
<property>
<name>fs.trash.interval</name>
<value>1440</value>
</property>
# 开启垃圾桶效果
[root@node1 hadoop]# hdfs dfs -rm -r /test1.har
2023-05-24 15:07:33,470 INFO fs.TrashPolicyDefault: Moved: 'hdfs://node1.itcast.cn:8020/test1.har' to trash at: hdfs://node1.itcast.cn:8020/user/root/.Trash/Current/test1.har
# 开启垃圾桶后并没有真正删除,还可以恢复
[root@node1 hadoop]# hdfs dfs -mv /user/root/.Trash/Current/test1.har /