分区&分桶
分区
为什么有分区?
随着系统运行时间增长,表的数据量越来越大,而hive查询时通常是是全表扫描,这样将导致大量的不必要的数据扫描,从而大大减低查询效率。
从而引进分区技术,使用分区技术,避免hive全表扫描,提升查询效率。
可以将用户的整个表的数据在存储时划分到多个子目录,从而在查询时可以指定查询条件(子目录以分区变量的值来命名)eg:year=‘2018’。
怎么分区?
根据业务,通常按照年、月、日、地区等
分区的技术?
PARTIONED BY(col_name data_type)
hive的分区字段使用的是表外字段。而mysql使用的是表内字段。
1、hive的分区名区分大小写
2、hive的分区本质是在表目录下面创建目录,但是该分区字段是一个伪列,不真实存在于数据中
3、一张表可以有一个或者多个分区,分区下面也可以有一个或者多个分区
分区的意义?
可以让用户在做数据分析统计时缩小数据扫描的范围,因为可以在select时指定要统计的分区,提高查询效率。
创建分区表
一级:
create table if not exists part1(
uid int,
uname string,
uage int
)
PARTITIONED BY (country string)
row format delimited
fields terminated by ','
;
分区表导入数据的方式:
load data local inpath '/usr/local/xxx' into table part1
partition(country='China'); #要指定分区
select * from part1 where country='China';
二级:
create table if not exists part2(
uid int,
uname string,
uage int
)
PARTITIONED BY (year string,month string)
row format delimited
fields terminated by ','
;
load data local inpath '/usr/local/xxx' into table part1
partition(year='2018',month='09');
load data local inpath '/usr/local/xxx' into table part1
partition(year='2018',month=09);
select * from part2 where year='2018',month='09';
三级:
create table if not exists part3(
uid int,
uname string,
uage int
)
PARTITIONED BY (year string,month string,day string)
row format delimited
fields terminated by ','
;
load data local inpath '/usr/local/xxx' into table part3
partition(year='2018',month='09',day='29');
load data local inpath '/usr/local/xxx' into table part3
partition(year='2018',month=09,day='29');
select * from part3 where year='2018',month='09',day='29';
显示分区:
show partitions part3;
修改分区:
分区名不能使用命令修改(手动修改),文件名+元数据
增加分区:
alter table part1 add partition(country='india');
增加多个分区:
alter table part1 add partition(country='india') partition(country='korea') partition(country='America');
增加分区并设置数据:
alter table part1 add partition(country='Vietnam')
location '/user/hive/warehouse/xxx'
;
增加分区并设置数据:
location 跟在 partition之后,空格隔开
修改分区的存储路径:(hdfs的路径必须是全路径)
alter table part1 partition(country='Vietnam') set location ‘hdfs://hadoop01:9000/user/hive/warehouse/brz.db/part1/country=Vietnam’
删除分区:
alter table part1 drop partition(country='india');
alter table part1 drop partition(country='india'),partition(country='korea'),partition(country='America'); ##逗号隔开
分区类型:
1、静态分区:加载数据到指定的分区值
2、动态分区:数据未知,根据分区的值确定创建分区
3、混合分区:静态和动态都有
动态分区的属性:
set hive.exec.dynamic.partition=true;//(true/false)
set hive.exec.dynamic.partition.mode=strict;//(strict/nonstrict) 至少有一个静态的值
set hive.exec.dynamic.partitions=1000;//(分区最大数)
set hive.exec.max.dynamic.partitions.pernode=100
创建动态分区:
create table if not exists dt_part1(
uid int,
uname string,
uage int
)
PARTITIONED BY (year string,month string)
row format delimited
fields terminated by ','
;
加载数据:(不能使用load加载数据)
load data local inpath '/usr/local/xxx' into table part1
partition(year,month);
加载数据:(使用 insert into方式加载数据)
1、创建临时表
create table if not exists part_tmp(
uid int,
uname string,
uage int,
year string,
month string
)
row format delimited
fields terminated by ','
;
2、insert into方式加载数据
insert into dy_part1 partition(year,month)
select * from part_tmp
;
混合:(注意列的个数的匹配)
create table if not exists dy_part2(
uid int,
uname string,
uage int
)
PARTITIONED BY (year string,month string)
row format delimited
fields terminated by ','
;
insert into dy_part2 partition(year='2018',month)
select uid,uname,uage,month from part_tmp
;
###设置hive的执行模式:
1、严格模式:
set hive.mapred.mode=nonstrict/strict
In strict mode, some risky queries are not allowed to run. They include:
Cartesian Product.
No partition being picked up for a query.
Comparing bigints and strings.
Comparing bigints and doubles.
Orderby without limit.
注意事项:
1、hive的分区使用的表外字段,分区字段是一个伪列但是可以查询过滤。
2、分区字段不建议使用中文
3、不太建议使用动态分区。因为动态分区将会使用mapreduce来查询数据,如果分区数量过多将导致namenode和yarn的资源瓶颈。所以建议动态分区前也尽可能之前预知分区数量。
4、分区属性的修改均可以使用手动元数据和hdfs的数据内容
分桶
为什么要分桶?
单个分区或者表中的数据量越来越大,当分区不能更细粒的划分数据时,所以会采用分桶技术将数据更细粒度的划分和管理。
分桶技术
[CLUSTERED BY (col_name, col_name, ...)
[SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
关键字:BUCKET
分桶的意义 ###:
1、为了保存分桶查询结果的分桶结构(数据已经按照分桶字段进行了hash散列)
2、分桶表数据进行抽样和JOIN时可以提高MR程序效率
分桶表的使用 ###:
1、创建一个带分桶定义的表(分桶表)
create table if not exists buc1(
uid int,
uname string,
uage int
)
clustered by (uid) into 4 buckets
row format delimited
fields terminated by ','
;
加载数据:
load data local inpath '/usr/local/hive/test/3.txt' into table buc1
;
设置强制分桶属性:
set hive.enforce.bucketing=false/true
如果reduce的个数和分桶的个数不一致时,请手动设置reduce的个数:
设置reduce task的个数:
set mapreduce.job.reduces=4;
分桶查询测试:
select * from buc1
cluster by (uid)
;
创建临时表:
create table if not exists buc_temp(
uid int,
uname string,
uage int
)
row format delimited
fields terminated by ','
;
加载数据:
load data local inpath '/usr/local/hivedata/3.txt' into table buc_temp
;
创建分桶表:
create table if not exists buc2(
uid int,
uname string,
uage int
)
clustered by (uid) into 4 buckets
row format delimited
fields terminated by ','
;
分桶表数据需要使用insert into 方式来加载:
insert overwrite table buc2
select uid,uname,uage from buc_temp
cluster by (uid)
;
创建分桶表,并且指定排序字段及排序规则
create table if not exists buc3(
uid int,
uname string,
uage int
)
clustered by (uid)
sorted by (uid desc) into 4 buckets
row format delimited
fields terminated by ','
;
导入数据:
insert overwrite table buc3
select uid,uname,uage from buc_temp
cluster by (uid)
;
insert overwrite table buc3
select uid,uname,uage from buc_temp
distribute by (uid) sort by (uid asc)
;
insert overwrite table buc3
select uid,uname,uage from buc_temp
distribute by (uid) sort by (uid desc)
;
insert overwrite table buc3
select uid,uname,uage from buc_temp
distribute by (uid) sort by (uage desc)
;
对分桶表的查询 :
1、查询全部:
select * from buc3;
select * from buc3 tablesample(bucket 1 out of 1)
查询第几桶:
select * from buc3 tablesample(bucket 1 out of 4 on uid); //除4余0
select * from buc3 tablesample(bucket 1 out of 2 on uid);
解释一下:
tablesample(bucket x out of y on uid)
x:代表从第几桶开始查询
y:查询的总桶数,y可以是总的桶数的倍数或者因子;x不能大于y
不压缩不拉伸:1 out of 4
for 1 to 4
1 2 3 4 1 2 3 4
1 1 + 4
压缩: 1 out of 2
1 2 3 4
1 2 1 2 1 2
1 1 + 4/2 1+4/2+4/2
拉伸:1 out of 8
1 2 3 4 5 6 7 8
1 2 3 4
等于是重新对所有数据进行分桶:
例子:
查询uid为奇数:(tablesample一定要紧跟在表名之后)
select * from buc3 tablesample(bucket 2 out of 2 on uid)
查询:
select * from part_tmp limit 3;
select * from part_tmp tablesample(3 rows);
select * from part_tmp tablesample(13 percent);
select * from part_tmp tablesample(56B); ###k B M G T P
随机查询3条数据:
select * from part_tmp order by rand() limit 3;
select rand() as rand1,* from part_tmp;
分桶总结:
1、定义:
clustered by (uid) – 指定分桶的字段
sorted by (uid desc) – 指定数据的排序规则,表示预期的数据就是以这里设置的字段以及排序规则来进行存储
2、导数据
cluster by (uid) – 指定getPartition以哪个字段来进行hash散列,并且排序字段也是指定的字段,默认以正序进行排序
distribute by(uid) – 指定getPartition以哪个字段来进行hash散列
sort by(uid asc) – 指定排序字段,以及排序规则
–更灵活的方式,这种数据获取方式可以分别指定getPartition的字段和sort的字段
cluster by (uid)与distribute by(uid) sort by (uid asc)结果是一样的
分区下的分桶:
举例说明一下:按照性别进行分区(1男2女),在分区中按照uid的奇偶进行分桶:
1 gyy1 1
2 gyy2 2
3 gyy3 2
4 gyy4 1
5 gyy5 2
6 gyy6 1
7 gyy7 1
8 gyy8 2
9 gyy9 1
10 gyy10 1
11 gyy11 2
12 gyy12 1
1、创建临时表:
create table if not exists stu_temp(
uid int,
uname string,
usex int
)
row format delimited
fields terminated by ' '
;
加载数据:
load data local inpath '/usr/local/hivedata/stu.dat' into table stu_temp;
创建分区分桶表:
create table if not exists stus(
uid int,
uname string
)
partitioned by (sex int)
clustered by (uid) into 2 buckets
row format delimited
fields terminated by ' '
;
//insert into方式:
insert into table stus partition(sex)
select uid,uname,usex from stu_temp
cluster by (uid)
;
需求:
查询性别为女性的、并且学号为奇数的学生:
select *
from stus tablesample(bucket 2 out of 2 on uid)
where sex=2;
注意:
1、分区使用的是表外字段,分桶使用的是表内字段
2、分桶是更细粒度的划分、管理数据,更多用来做数据抽样、JOIN操作