一、分区表和分桶表
1.1 分区表partition
hive中的分区就是把一张大表的数据按照业务需要分散的存储到多个目录,每个目录就称为该表的一个分区。在查询时通过where子句中的表达式选择式选择查询所需要的分区,这样的查询效率辉提高很多。
1.1.1 分区表基本语法
a. 创建分区表
create table dept_partition(
deptno int,
dname string,
loc string
)
partitioned by (day string)
row format delimited fields terminated by '\t'
lines terminated by '\n';
b. 分区表读写数据
写数据--load
load data local inpath '/opt/stufile/dept_20230225.log'
into table dept_partition
partition (day='20230225')
写数据--insert
insert overwrite table dept_partition partition (day='20230226')
select deptno,dname,loc from dept_partition where day='20230225';
读数据
查询分区表数据时,可以将分区字段看作表的伪劣,可像使用其他字段一样使用分区字段。
select deptno,dname,loc,day
from dept_partition
where day='2020-04-01'
c. 分区表基本操作
查看所有分区信息
show prtitions dept_partition;
增加分区
创建单个分区
alter table dept_partition
add partition(day='20220403');
同时创建多个分区(分区之间不能有逗号)
alter table dept_partition
add partition(day='20220404') partition(day='20220405');
删除分区
删除单个分区
alter table dept_partition
drop partition(day='20220403');
同时删除多个分区(分区之间必须有逗号)
alter table dept_partition
drop partition(day='20220404'), partition(day='20220405');
d. 修复分区
Hive 将分区表的所有分区信息都保存在了元数据中,只有元数据与 HDFS 上的分区路径一致时,分区表才能正常读写数据。若用户手动创建/删除分区路径,Hive 都是感知不到的,这样就会导致 Hive 的元数据和 HDFS 的分区路不一致。再比如,若分区表为外部表用户执行 drop partition 命令后,分区元数据会被删除,而 HDFS 的分区路径不会被删除同样会导致 Hive 的元数据和 HDFS 的分区路径不一致。
若出现元数据和 HDFS 路径不一致的情况,可通过如下几种手段进行修复:
add partition
若手动创建HDFS 的分区路径,Hive 无法识别,可通过add partition 命令增加分区元数据信息,从而使元数据和分区路径保持一致。
drop partition
若手动删除 HDFS 的分区路径,Hive 无法识别,可通过 drop partition 命令删除分区元数据信息,从而使元数据和分区路径保持一致。
msck
若分区元数据和 HDFS 的分区路径不一致,还可使用 msck 命令进行修复。
msck repair table table_name [add/drop/sync partitions];
1.1.2 二级分区表
如果一天内的日志数据量也很大,可以创建二级分区表,例如可以在按天分区的基础上,再对每天的数据按小时进行分区。
二级分区表建表语句
create create table dept partition2(
dleptno int,
dnamne string,,
loc string
partitioned by (day string, hour string)
row format delimited fields terminated by '\t';
数据装载语句
load data local inpath '/opt/stufile/dept_20220401.log'
into table dept_partition
partition (day='20220401', hour='12');
查询分区数据
select *
from dept_partition2
where day='20220401' and hour='12';
1.1.3 动态分区
动态分区是指向分区表 insert 数据时,被写往的分区不由用户指定,而是由每行数据的最后一个宁段的值来动态的决定。使用动态分区,可只用一个 insert 语句将数据写入多个分区。
动态分区相关参数
1. 动态分区功能总开关(默认 true,开启)
set hive.exec.dynamic.partition=true
2. 严格模式和非严格模式
-> 动态分区的模式,默认 strict(严格模式),要求必须指定至少一个分区为静态分区,
-> nonstrict(非严格模式) 允许所有的分区字段都使用动态分区。
set hive.exec.dynamic.partition.mode=nonstrict
3. 一条 insert 语句可同时创建的最大的分区个数,默认为 1000。
set hive.exec.max.dynamic.partitions=1000
4. 单个 Mapper 或者 Reducer 可同时创建的最大的分区个数,默认为 100。
set hive.exec.max.dynamic.partitions.pernode=100
5. 一条 insert 语句可以建的最大的文件个数,默认 100000
hive.exec.max.created.files=100000
6. 当查询结果为空时且进行动态分区时,是否抛出异常,默认 false。
hive.error.on.empty.partition=false
1.2 分桶表bucket
分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区。对于一张表或者分区,Hive 可以进一步组织成桶,也就是更为细粒度的数据范围划分,分区针对的是数据的存储路径,分桶针对的是数据文件。
分桶表的基本原理是,首先为每行数据计算一个指定字段的数据的 hash 值,然后模以·个指定的分桶数,最后将取模运算结果相同的行,写入同一个文件中,这个文件就称为一个分桶(bucket)。
1.2.1 分桶表基本语法
建表语句
create table stu buck(
id int,
name string
)
clustered by(id)
into 4 buckets
row format delimited fields terminated by '\t';
数据装载
load data local inpath '/opt/module/hive/datas/student.txt'
into table stu_buck;
1.2.2 分桶排序表
建表语句
create table stu buck(
id int,
name string
)
clustered by(id) sorted by(id)
into 4 buckets
row format delimited fields terminated by '\t';
数据装载
load data local inpath '/opt/module/hive/datas/student.txt'
into table stu_buck_sort;
二、文件格式和压缩
2.1hive文件格式
为 Hive 表中的数据选择一个合适的文件格式,对提高查询性能的提高是十分有益的。Hive 表数据的存储格式,可以选择 text file、orc、parquet、sequence file 等。
2.1.1 Text File
文本文件是 Hive 默认使用的文件格式,文本文件中的一行内容,就对应 Hive 表中的行记录。
可通过以下建表语句指定文件格式为文本文件:
create table textfile_table
(column specs)
stored as textfile;
2.1.2 ORC
ORC (Optimized Row Columnar) file format 是 Hive 0.11版里引入的一种列式存储的文件格式。ORC文件能够提高 Hive 读写数据和处理数据的性能。
与列式存储相对的是行式存储,下图是两者的对比:
行存储的特点
查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。
列存储的特点
因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法。
前文提到的 text file 和 sequence file 都是基于行存储的,orc 和 parquet 是基于列式存储的。
每个Orc 文件由 Header、Body 和 Tail 三部分组成。
其中Header内容为ORC,用于表示文件类型。
Body由1个或多个 stripe 组成,每个 stripe 一般为 HDFS 的块大小,每一个 stripe 包含多条记录,这些记录按照列进行独立存储,每个 stripe 里有三部分组成,分别是 index Data, Row Data,Stripe Footere。
index Data:一个轻量级的 index,默认是为各列每隔 1w 行做一个索引。每个索引会Index Data:记录第n万行的位置,和最近一万行的最大值和最小值等信息。
Row Data:存的是具体的数据,按列进行存储,并对每个列进行编码,分成多个Stream 来存储。
Stripe Footer:存放的是各个Stream 的位置以及各 column 的编码信息。
Tail 由File Footer PostScript 组成。File Footer 中保存了各 Stripe 的其实位置、索引长度、数据长度等信息,各 Column 的统计信息等;PostScript 记录了整个文件的压缩类型以及Fle Footer 的长度信息等。
在读取ORC 文件时,会先从最后一个字节读取 PostScript 长度,进而读取到 PostScript,从里面解析到 File Footer 长度,进而读取 FileFooter,从中解析到各个Stripe信息,再读各个stripe,即从后往前读。
建表语句
create table orc table
(column specs)
stored as orc
tblproperties (property_name=property value, ...) ;
ORC文件格式支持的参数如下:
参数 | 默认值 | 说明 |
orc.compress | ZLIB | 压缩格式,可选项:NONE、ZLIB、SNAPPY |
orc.compress.size | 262,144 | 每个压缩快的大小(ORC文件是分块压缩的) |
orc.tripe.size | 67,108,864 | 每个stripe的大小 |
orc.row.index.stride | 10,000 | 索引步长(每隔多少行数据建一条索引) |
2.13 Parqust
Parquet 文件是 Hadoop 生态中的一个通用的文件格式,它也是一个列式存储的文件格式。
建表语句
create table parquet_table
(column specs)
stored as parcuet
tbproperties (property_name=propertu_value, ...);
支持的参数如下:
参数 | 默认值 | 说明 |
parquet.compression | uncompressed | 压缩格式,可选项:uncompressed,snappy,gzip,lzo,brotli,lz4 |
parquet.block.size | 134217728 | 行组大小,通常与HDFS块大小保持一致 |
parquet.page.size | 1048576 | 页大小 |
2.2 压缩
在 Hive 表中和计算过程中,保持数据的压缩,对磁盘空间的有效利用和提高查询性能都是十分有益的。
2.2.1 hive表数据进行压缩
在 Hive 中,不同文什类型的表,声明数据压缩的方式是不同的。
TextFile
若一张表的文件类型为 TextFile,若需要对该表中的数据进行压缩,多数情况下,无需在建表语句做出声明。直接将压缩后的文件导入到该表即可,Hive 在查询表中数据时,可自动识别其压缩格式,进行解压。
需要注意的是,在执行往表中导入数据的 SQL 语句时,用户需设置以下参数,来保证写入表中的数据是被压缩的。
——SQL语句的最终输出结果是否压缩
set hive.exec.compress.output=true;
——输出结果的压缩格式
set mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;
ORC
若一张表的文件类型为 ORC,若需要对该表数据进行压缩,需在建表语句中声明压缩,格式如下:
create table orc table
(column specs)
stored as orc
tblproperties("orc.compress"="snappy");
Parquet
若一张表的文件类型为 parquet,若需要对该表数据进行压缩,需在建表语句中声明压缩,格式如下:
create table orc table
(column specs)
stored as parquet
tblproperties("parquet.compress"="snappy");
2.2.2 计算过程中使用压缩
单个MR的中间结果进行压缩
单个MR 的中间结果是指 Mapper 输出的数据,对其进行压缩可降低 shuffle 阶段的网络10,可通过以下参数进行配置:
——开启MapReduce中间数据压缩功能
set mapreduce.map.output.compress=true;
——设置MapReduce中间数据的压缩方式
set mapreduce.map.output.codec=org.apache.hadoop.io.compress.SnappyCodec;
单条SQL语句的中间结果进行压缩
单条 SQL 语句的中间结果是指,两个 MR(一条 SQL 语可能需要通过 MR 进行计算)之间的临时数据,可通过以下参数进行配置:
——是否对两个MR 之间的临时数据进行压缩
set hive.exec.compress .intermediate=true;
——压缩格式(以下示例为 snappy)
set hive.intermediate.compression.codec=org.apache.hadoop.io.compress.SnappyCodec;