从这里开始就是hive调优阶段,怎么让hive跑的更快。
分区表和分桶表都是从存储方向进行优化。
目录
[(1)add partition](#(1)add partition)
[(2)drop partition](#(2)drop partition)
分区表:
概念:
Hive中的分区就是把一张大表的数据按照业务需要分散的存储到多个目录(hdfs中的不同目录下),每个目录就称为该表的一个分区。在查询时通过where子句中的表达式选择查询所需要的分区,这样的查询效率会提高很多。
代码:
java
create table dept_partition
(
deptno int, --部门编号
dname string, --部门名称
loc string --部门位置
)
partitioned by (day string)
row format delimited fields terminated by '\t';
上述代码创建了分区表,创建后的表是有4个字段以(day string)进行分区
load填充数据:
sql
load data local inpath '/opt/module/hive/datas/dept_20220401.log'
into table dept_partition
partition(day='20220401');
可以看到与原来的load语句有不一样的地方---后边多出来partition(day='20220401')
这个就是进行分区的字段 直接填充入该分区内(我们填充数据的源文件是没有这个字段的)
查询结果:可以看出是查询的四个字段的数据
insert+select填充数据:
需求:
把分区为0401分区的数据复制一份到0402分区中
sql
insert overwrite table dept_partition partition (day='20220402')
select
deptno,
dname,
loc
from dept_partition where day='20220401';
分区表基本操作
(一)查看所有分区信息
sql
show partitions dept_partition;
(二)增加分区
(1)创建单个分区
sql
alter table dept_partition
add partition(day='20220403');
(2)同时创建多个分区(分区之间不能有逗号)
sql
alter table dept_partition
add partition(day='20220404') partition(day='20220405');
添加分区后不尽会在hive上创建相应路径,而且还会在元数据中体现(mysql)分区也是元数据的一种。
(三)删除分区
(1)删除单个分区
sql
alter table dept_partition
drop partition (day='20220403');
(2)同时删除多个分区(分区之间必须有逗号)
sql
alter table dept_partition
drop partition (day='20220404'), partition(day='20220405');
删除分区也是删除hdfs路径与元数据
分区表也是有内部表(管理表)与外部表之分的
外部分区表删除分区的时候也是只删除MySQL(元数据),不删除hdfs路径
(四)修复分区
Hive将分区表的所有分区信息都保存在了元数据中,只有元数据与HDFS上的分区路径一致时,分区表才能正常读写数据。若用户手动创建/删除分区路径,Hive都是感知不到的,这样就会导致Hive的元数据和HDFS的分区路径不一致。再比如,若分区表为外部表,用户执行drop partition命令后,分区元数据会被删除,而HDFS的分区路径不会被删除,同样会导致Hive的元数据和HDFS的分区路径不一致。
若出现元数据和HDFS路径不一致的情况,可通过如下几种手段进行修复。
(1)add partition
若手动创建HDFS的分区路径,Hive无法识别,可通过add partition命令增加分区元数据信息,从而使元数据和分区路径保持一致。
在hive创建对应分区:
sql
alter table dept_partition
add partition (day='20220403')
(2)drop partition
若手动删除HDFS的分区路径,Hive无法识别,可通过drop partition命令删除分区元数据信息,从而使元数据和分区路径保持一致。
同上操作
无论是删除还是补充都是以hdfs的路径为准
(3)msck
若分区元数据和HDFS的分区路径不一致,还可使用msck命令进行修复,以下是该命令的用法说明。
造成不一致的原因:
-
分区信息未正确更新:如果你在创建、删除或更改表的分区时没有正确更新Hive元数据或其他管理工具中的分区信息,就会导致分区元数据与HDFS中的实际分区路径不一致。
-
目录操作错误:如果你通过直接使用文件系统命令而不是使用Hive或其他管理工具来创建、删除或移动分区目录,就可能导致分区元数据和HDFS分区路径之间的不一致。
-
数据丢失或损坏:如果在HDFS上删除了某个分区的数据或数据发生了损坏,但分区元数据中仍然存在对该分区的引用,就会导致分区元数据和实际分区路径不匹配。
-
分区数据的外部更改:如果你在HDFS上手动更改了某个分区的数据目录结构或文件内容,而没有相应地更新分区元数据,就会导致分区元数据和HDFS分区路径之间的不一致。
代码:
sql
msck repair table table_name [add/drop/sync partitions];
说明:
msck repair table table_name add partitions:该命令会增加HDFS路径存在但元数据缺失的分区信息。(会增加所有需要增加的分区信息)
msck repair table table_name drop partitions:该命令会删除HDFS路径已经删除但元数据仍然存在的分区信息。(会删除所有需要删除的分区信息)
msck repair table table_name sync partitions:该命令会同步HDFS路径和元数据分区信息,相当于同时执行上述的两个命令。(会删除所有需要删除的分区信息 and 会增加所有需要增加的分区信息)
默认:
msck repair table table_name:等价于msck repair table table_name add partitions命令。
(五)二级分区
项目中绝大多数是按日期进行分区的(一天一个分区,每个分区只保存当天的数据)
二级分区就是在创建表的时候标注出两个分区字段
eg:我们每天是一个分区,在每个分区中按每个小时进行分区
创建表:
sql
create table dept_partition2(
deptno int, -- 部门编号
dname string, -- 部门名称
loc string -- 部门位置
)
partitioned by (day string, hour string)
row format delimited fields terminated by '\t';
一级分区写在前面,二级分区写在后边
数据载入;
load:
sql
load data local inpath '/opt/module/hive/datas/dept_20220401.log'
into table dept_partition2
partition(day='20220401', hour='12');
(六)动态分区
动态分区是指向分区表insert数据时,被写往的分区不由用户指定,而是由每行数据的最后一个字段的值来动态的决定。使用动态分区,可只用一个insert语句将数据写入多个分区。
(动态分区通俗来说就是架构根据你设置的分区字段来进行自动分配)
(分区多,索引慢,分区少,查询慢)
1)动态分区相关参数
(1)动态分区功能总开关(默认true,开启)
sql
set hive.exec.dynamic.partition=true
(2)严格模式和非严格模式
动态分区的模式,默认strict(严格模式),要求必须指定至少一个分区为静态分区,nonstrict(非严格模式)允许所有的分区字段都使用动态分区。
sql
set hive.exec.dynamic.partition.mode=nonstrict
(3)一条insert语句可同时创建的最大的分区个数,默认为1000。
sql
set hive.exec.max.dynamic.partitions=1000
(4)单个Mapper或者Reducer可同时创建的最大的分区个数,默认为100。
sql
set hive.exec.max.dynamic.partitions.pernode=100
(5)一条insert语句可以创建的最大的文件个数,默认100000。
sql
hive.exec.max.created.files=100000
(6)当查询结果为空时且进行动态分区时,是否抛出异常,默认false。
sql
hive.error.on.empty.partition=false
eg需求:
将dept表中的数据按照地区(loc字段),插入到目标表dept_partition_dynamic的相应分区中。
(1)建表:
sql
create table dept_partition_dynamic(
id int,
name string
)
partitioned by (loc int)
row format delimited fields terminated by '\t';
(2)设置动态分区:
先设置非严格模式:
sql
set hive.exec.dynamic.partition.mode = nonstrict;
导入数据:
sql
insert into table dept_partition_dynamic
partition(loc)
select
deptno,
dname,
loc
from dept;
查看表的分区情况:
sql
show partitions dept_partition_dynamic;
分桶表:
概念:
分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区。对于一张表或者分区,Hive 可以进一步组织成桶,也就是更为细粒度的数据范围划分,分区针对的是数据的存储路径,分桶针对的是数据文件。
分桶表的基本原理是,首先为每行数据计算一个指定字段的数据的hash值,然后模以一个指定的分桶数,最后将取模运算结果相同的行,写入同一个文件中,这个文件就称为一个分桶(bucket)。
操作:
声明分桶字段:
分区字段与分桶字段不能是相同的字段
分区字段不是普通的建表字段,而分桶字段是来自普通的建表字段,可参考上下文的建表语句
sql
clustered by(id)
设置分桶数(用于取模运算):
sql
into 4 buckets
建表:
sql
create table stu_buck(
id int,
name string
)
clustered by(id)
into 4 buckets
row format delimited fields terminated by '\t';
使用load语句进行导入数据:
sql
load data local inpath '/opt/module/hive/datas/student.txt'
into table stu_buck;
运行结果可知在hdfs路径下的文件夹下创建了4个文件(设置了4个桶)---这是因为在hive3进行了升级,在导入数据的时候可以直接执行mapreduce程序,而老版本则是不能直接问创建分区表,需要先创建普通的表导入数据后在通过insert--select语句进行分桶操作。
分桶排序表:
分桶排序表是对每个分桶中的数据进行排序,只需要在建表语句中的分桶字段的后边添加一个桶内排序字段,不要求两个字段一致,个数也不一定是1个。
建表语句:
sql
create table stu_buck_sort(
id int,
name string
)
clustered by(id) sorted by(id)
into 4 buckets
row format delimited fields terminated by '\t';
导入数据:
sql
load data local inpath '/opt/module/hive/datas/student.txt'
into table stu_buck_sort;
导入后便可通过hdfs的web端进行查看桶内数据情况。