分区和分桶区别

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了分区和分桶区别相关的知识,希望对你有一定的参考价值。

参考技术A

我们知道在传统的DBMs系统中,一般都具有表分区的功能,通过表分区能够在特定的区域检索数据,减少扫描成本,在一定程度上提高了查询效率,当然我们还可以通过进一步在分区上建立索引,进一步提高查询效率。

在Hive中的数据仓库中,也有分区分桶的概念,在逻辑上,分区表与未分区表没有区别,在物理上分区表会将数据按照分区间的列值存储在表目录的子目录中,目录名=“分区键=键值”。其中需要注意的是分区键的列值存储在表目录的子目录中,目录名=“分区键=键值”。其中需要注意的是分区键的值不一定要基于表的某一列(字段),它可以指定任意值,只要查询的时候指定相应的分区键来查询即可。我们可以对分区进行添加、删除、重命名、清空等操作。

分桶则是指定分桶表的某一列,让该列数据按照哈希取模的方式随机、均匀的分发到各个桶文件中。因为分桶操作需要根据某一列具体数据来进行哈希取模操作,故指定的分桶列必须基于表中的某一列(字段)。分桶改变了数据的存储方式,它会把哈希取模相同或者在某一个区间的数据行放在同一个桶文件中。如此一来便可以提高查询效率。如果我们需要对两张在同一个列上进行了分桶操作的表进行JOIN操作的时候,只需要对保存相同列值的通进行JOIN操作即可。

还有一点需要点一下:在hive中的数据是存储在hdfs中的,我们知道hdfs中的数据是不允许修改只能追加的,那么在hive中执行数据修改的命令时,就只能先找到对应的文件,读取后执行修改操作,然后重新写一份文件。如果文件比较大,就需要大量的IO读写。在hive中采用了分桶的策略,只需要找到文件存放对应的桶,然后读取再修改写入即可。

分区:

hive中分区分为 : 单值分区、范围分区。

单值分区: 静态分区 动态分区

如下所示,现在有一张persionrank表,记录每个人的评级,有id、name、score字段。我们可以创建分区rank(rank不是表中的列,我们可以把它当做虚拟列),并将相应的数据导入指定分区(将数据插入指定目录)。

单值分区:

单值静态分区:导入数据时需要 手动指定分区

单值动态分区:导入数据时,系统可以动态判断目标分区

1.静态分区创建:

直接在PARTITI1ONED BY后面跟上分区键、类型即可(指定的分区键不能出现在定义列名中)

2.静态分区写入:

3.添加分区:

4.删除分区:

5.修复分区:

6.动态分区创建:

创建方式与静态分区表完全一样,一张表可同时被静态分区和动态分区键分区,只是动态分区键需要放在静态分区键的后面(HDFS上的动态分区目录下不能包含静态分区的子目录),如下spk即static partition key(静态分区键),dpk为dynamic partition key(动态分区键)

7.动态分区写入:

根据表中的某一个列值来确定hdfs存储的目录:

优点:

动态可变,不需要人为控制。假如设定的是日期,那么每一天的数据会单独存储在一个文件夹中

缺点:

需要依靠MR完成,执行比较慢

静态分区键要用 <spk>=<value> 指定分区值;动态分区只需要给出分出分区键名称 <dpk>。

范围分区:

单值分区每个分区对应于分区键的一个取值,而 每个范围分区则对应分区键的一个区间 ,只要落在指定区间内的记录都被存储在对应的分区下。 分区范围需要手动指定,分区的范围为前闭后开区间 [最小值, 最大值) 。最后出现的分区可以使用 MAXVALUE 作为上限,MAXVALUE 代表该分区键的数据类型所允许的最大值。

多个范围分区键的情况:

分桶:

对Hive(Inceptor)表分桶可以将表中记录按分桶键的哈希值分散进多个文件中,这些小文件称为桶。

1.创建分桶表:

分桶表的建表有三种方式:直接建表,CREATE TABLE LIKE 和 CREATE TABLE AS SELECT , 单值分区表不能用 CREATE TABLE AS SELECT 建表 。这里以直接建表为例:

分桶键只能有一个即<col_name>。表可以同时分区和分桶, 当表分区时,每个分区下都会有<num_buckets> 个桶 。我们也可以选择使用 SORTED BY … 在桶内排序,排序键和分桶键无需相同。ASC 为升序选项,DESC 为降序选项, 默认排序方式是升序 <num_buckets> 指定分桶个数 ,也就是表目录下小文件的个数。

2.向分桶表中写数据:

因为分桶表在创建的时候只会定义Scheme,且写入数据的时候不会自动进行分桶、排序,需要人工先进行分桶、排序后再写入数据。确保目标表中的数据和它定义的分布一致。

目前有两种方式往分桶表中插入数据:

方法一:打开enforce bucketing开关。

方法二:将reducer个数设置为目标表的桶数,并在 SELECT 语句中用 DISTRIBUTE BY <bucket_key>对查询结果按目标表的分桶键分进reducer中。

如果分桶表创建时定义了排序键,那么数据不仅要分桶,还要排序

如果分桶键和排序键不同,且按降序排列,使用Distribute by … Sort by分桶排序

如果分桶键和排序键相同,且按升序排列(默认),使用 Cluster by 分桶排序,即如下:

抽样语句 :tablesample(bucket x out of y)

tablesample是抽样语句,语法:tablesample(bucket x out of y),y必须是table总共bucket数的倍数或者因子。Hive根据y的大小,决定抽样的比例。例如:table总共分了64份,当y=32时,抽取2(64/32)个bucket的数据,当y=128时,抽取1/2(64/128)个bucket的数据。x表示从哪个bucket开始抽取。例如:table总共bucket数为32,tablesample(bucket 3 out of 16)表示总共抽取2(32/16)个bucket的数据,分别为第三个bucket和第19(3+16)个bucket的数据。

分区表和分桶表

第10章 分区表和分桶表

10.1 分区表

Hive中的分区就是把一张大表的数据按照业务需要分散的存储到多个目录,每个目录就称为该表的一个分区。在查询时通过where子句中的表达式选择查询所需要的分区,这样的查询效率会提高很多。

10.1.1 分区表基本语法

1.创建分区表

create table dept_partition
(
    deptno int,    --部门编号
    dname  string, --部门名称
    loc    string  --部门位置
)
    partitioned by (day string)
    row format delimited fields terminated by '\\t';

2.分区表读写数据

1)写数据

(1)load

数据准备

/opt/module/hive/datas/ 路径上创建文件 dept_20220401.log,并输入如下内容。

[atguigu@hadoop102 datas]$ vim dept_20220401.log

10	行政部	1700
20	财务部	1800

装载语句

load data local inpath '/opt/module/hive/datas/dept_20220401.log' 
into table dept_partition 
partition(day='20220401');

(2)insert

day='20220401' 分区的数据插入到 day='20220402' 分区,可执行如下装载语句

insert overwrite table dept_partition partition (day = '20220402')
select deptno, dname, loc
from dept_partition
where day = '20220401';

2)读数据

查询分区表数据时,可以将分区字段看作表的伪列,可像使用其他字段一样使用分区字段。

select deptno, dname, loc ,day
from dept_partition
where day = '20220401';

3.分区表基本操作

1)查看所有分区信息

show partitions dept_partition;

2)增加分区

(1)创建单个分区

alter table dept_partition add partition(day='20220403');

(2)同时创建多个分区(分区之间不能有逗号)

alter table dept_partition add partition(day='20220404') partition(day='20220405');

3)删除分区

(1)删除单个分区

alter table dept_partition drop partition (day='20220403');

(2)同时删除多个分区(分区之间必须有逗号)

alter table dept_partition drop partition (day='20220404'), partition(day='20220405');

4)修复分区

Hive将分区表的所有分区信息都保存在了元数据中,只有元数据与HDFS上的分区路径一致时,分区表才能正常读写数据。若用户手动创建/删除分区路径,Hive都是感知不到的,这样就会导致Hive的元数据和HDFS的分区路径不一致。再比如,若分区表为外部表,用户执行 drop partition 命令后,分区元数据会被删除,而HDFS的分区路径不会被删除,同样会导致Hive的元数据和HDFS的分区路径不一致。

若出现元数据和HDFS路径不一致的情况,可通过如下几种手段进行修复。

(1)add partition

若手动创建HDFS的分区路径,Hive无法识别,可通过 add partition 命令增加分区元数据信息,从而使元数据和分区路径保持一致。

(2)drop partition

若手动删除HDFS的分区路径,Hive无法识别,可通过 drop partition 命令删除分区元数据信息,从而使元数据和分区路径保持一致。

(3)msck

若分区元数据和HDFS的分区路径不一致,还可使用 msck 命令进行修复,以下是该命令的用法说明。

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路径和元数据分区信息,相当于同时执行上述的两个命令。

msck repair table table_name:等价于msck repair table table_name **add** partitions命令。

10.1.2 二级分区表

思考:如果一天内的日志数据量也很大,如何再将数据拆分?答案是二级分区表,例如可以在按天分区的基础上,再对每天的数据按小时进行分区。

1)二级分区表建表语句

create table dept_partition2(
    deptno int,    -- 部门编号
    dname string, -- 部门名称
    loc string     -- 部门位置
)
partitioned by (day string, hour string)
row format delimited fields terminated by '\\t';

2)数据装载语句

load data local inpath '/opt/module/hive/datas/dept_20220401.log' 
into table dept_partition2 
partition(day='20220401', hour='12');

3)查询分区数据

select 
    * 
from dept_partition2 
where day='20220401' and hour='12';

10.1.3 动态分区

动态分区是指向分区表insert数据时,被写往的分区不由用户指定,而是由每行数据的最后一个字段的值来动态的决定。使用动态分区,可只用一个insert语句将数据写入多个分区。

1)动态分区相关参数

(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。

set hive.exec.max.created.files=100000;

(6)当查询结果为空时且进行动态分区时,是否抛出异常,默认false。

set hive.error.on.empty.partition=false;

2)案例实操

需求:将dept表中的数据按照地区(loc字段),插入到目标表dept_partition_dynamic的相应分区中。

(1)创建目标分区表

create table dept_partition_dynamic(
    id int, 
    name string
) 
partitioned by (loc int) 
row format delimited fields terminated by '\\t';

(2)设置动态分区

set hive.exec.dynamic.partition.mode = nonstrict;

insert into table dept_partition_dynamic 
partition(loc) 
select 
    deptno, 
    dname, 
    loc 
from dept

(3)查看目标分区表的分区情况

show partitions dept_partition_dynamic;

10.2 分桶表

分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理的分区。对于一张表或者分区,Hive 可以进一步组织成桶,也就是更为细粒度的数据范围划分,分区针对的是数据的存储路径,分桶针对的是数据文件。

分桶表的基本原理是,首先为每行数据计算一个指定字段的数据的hash值,然后模以一个指定的分桶数,最后将取模运算结果相同的行,写入同一个文件中,这个文件就称为一个分桶(bucket)。

10.2.1 分桶表基本语法

<property>
    <name>yarn.scheduler.capacity.maximum-am-resource-percent</name>
    <value>0.8</value>
</property>

1)建表语句

create table stu_buck(
    id int, 
    name string
)
clustered by(id) 
into 4 buckets
row format delimited fields terminated by '\\t';

2)数据装载

(1)数据准备

/opt/module/hive/datas/ 路径上创建 student.txt 文件,并输入如下内容。

vi /opt/module/hive/datas/student.txt

1001	student1
1002	student2
1003	student3
1004	student4
1005	student5
1006	student6
1007	student7
1008	student8
1009	student9
1010	student10
1011	student11
1012	student12
1013	student13
1014	student14
1015	student15
1016	student16

(2)导入数据到分桶表中

说明:Hive新版本load数据可以直接跑MapReduce,老版的Hive需要将数据传到一张表里,再通过查询的方式导入到分桶表里面。

load data local inpath '/opt/module/hive/datas/student.txt' 
into table stu_buck;

(3)查看创建的分桶表中是否分成4个桶

(4)观察每个分桶中的数据

10.2.2 分桶排序表

1)建表语句

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';

2)数据装载

(1)导入数据到分桶表中

load data local inpath '/opt/module/hive/datas/student.txt' 
into table stu_buck_sort;

(2)查看创建的分桶表中是否分成4个桶

(3)观察每个分桶中的数据

以上是关于分区和分桶区别的主要内容,如果未能解决你的问题,请参考以下文章

HIVE—索引分区和分桶的区别

分区表和分桶表

分区和分桶 Hive Table 有啥好处?

分区表和分桶表

Hive:第 7 章 分区表和分桶表

Hive里的分区和分桶再谈