hive分区分桶
1、分区
如果一个表中数据很多,我们查询时就很慢,耗费大量时间,如果要查询其中部分数据该怎么办呢,这时我们引入分区的概念。
Hive 中的分区表分为两种:静态分区和动态分区。
1.1、静态分区
可以根据 PARTITIONED BY 创建分区表。
一个表可以拥有一个或者多个分区,每个分区以文件夹的形式单独存在表文件夹的目录下。
- 一个分区:表目录下只有一级目录。
- 多个分区:表目录下是多级目录。
分区列是虚拟列,它们不是数据本身的一部分,而是在加载时派生的。
1.1.1、一个分区
-- 建表
create table order_table_s
(
order_id int, -- 订单id
product_name string, -- 产品名称
price int -- 产品价格
)
partitioned by (deal_day string) -- 交易日期YYYYMM
row format delimited
fields terminated by "\t";
-- 查看表结构
hive> desc order_table_s;
OK
order_id int
product_name string
price int
deal_day string
# Partition Information
# col_name data_type comment
deal_day string
-- 源数据
-- order-201901.txt
1 cellphone 2000
2 tv 3000
3 sofa 8000
4 cabinet 5000
5 bicycle 1000
6 truck 20000
-- order-201902.txt
1 apple 10
2 banana 8
3 milk 70
4 liquor 150
-- 导入数据
load data local inpath '/root/data/order-201901.txt' overwrite into table order_table_s partition(deal_day='201901');
load data local inpath '/root/data/order-201902.txt' overwrite into table order_table_s partition(deal_day='201902');
-- 查看表
hive> select * from order_table_s;
1 cellphone 2000 201901
2 tv 3000 201901
3 sofa 8000 201901
4 cabinet 5000 201901
5 bicycle 1000 201901
6 truck 20000 201901
1 apple 10 201902
2 banana 8 201902
3 milk 70 201902
4 liquor 150 201902
-- 查看201902的数据
hive> select * from order_table_s where deal_day='201902';
1 apple 10 201902
2 banana 8 201902
3 milk 70 201902
4 liquor 150 201902
-- 查看hdfs目录
[root@zgg data]# hadoop fs -ls /user/hive/warehouse/order_table_s
Found 2 items
drwxr-xr-x - root supergroup 0 2021-01-08 16:05 /user/hive/warehouse/order_table_s/deal_day=201901
drwxr-xr-x - root supergroup 0 2021-01-08 16:27 /user/hive/warehouse/order_table_s/deal_day=201902
[root@zgg data]# hadoop fs -ls /user/hive/warehouse/order_table_s/deal_day=201901
Found 1 items
-rw-r--r-- 1 root supergroup 56 2021-01-08 18:23 /user/hive/warehouse/order_table_s/deal_day=201901/000000_0
[root@zgg data]# hadoop fs -ls /user/hive/warehouse/order_table_s/deal_day=201901
Found 1 items
-rw-r--r-- 1 root supergroup 83 2021-01-08 16:05 /user/hive/warehouse/order_table_s/deal_day=201901/order-201901.txt
-- 查看mysql中的元数据
mysql> select * from PARTITION_KEY_VALS;
+---------+--------------+-------------+
| PART_ID | PART_KEY_VAL | INTEGER_IDX |
+---------+--------------+-------------+
| 16 | 201901 | 0 |
| 21 | 201902 | 0 |
+---------+--------------+-------------+
-- 删除分区201902
-- ALTER TABLE table_name DROP partition_spec, partition_spec,...
hive> alter table order_table_s drop partition(deal_day='201902');
-- 删除后,查看表
hive> select * from order_table_s;
1 cellphone 2000 201901
2 tv 3000 201901
3 sofa 8000 201901
4 cabinet 5000 201901
5 bicycle 1000 201901
6 truck 20000 201901
-- 删除后,查看hdfs目录
[root@zgg data]# hadoop fs -ls /user/hive/warehouse/order_table_s
Found 1 items
drwxr-xr-x - root supergroup 0 2021-01-08 16:05 /user/hive/warehouse/order_table_s/deal_day=201901
-- 删除后,查看mysql中的元数据
mysql> select * from PARTITION_KEY_VALS;
+---------+--------------+-------------+
| PART_ID | PART_KEY_VAL | INTEGER_IDX |
+---------+--------------+-------------+
| 16 | 201901 | 0 |
+---------+--------------+-------------+
-- 删除后,数据和元数据都被删除了
-- ---------------------------------------------------
-- 重新添加分区201902
-- 这里的location是这个分区的数据存放的位置,默认是`/user/hive/warehouse/order_table_s`
alter table order_table_s add partition(deal_day='201902') location '/in/order';
-- 把order-201902.txt移动到'/in/order'目录下
-- 所以导入数据,也可以直接复制到对应的目录下。
[root@zgg data]# hadoop fs -mv /in/order-201902.txt /in/order
-- 查看201902的数据
hive> select * from order_table_s where deal_day='201902';
1 apple 10 201902
2 banana 8 201902
3 milk 70 201902
4 liquor 150 201902
-- hive中查询分区
hive> show partitions order_table_s;
deal_day=201901
deal_day=201902
-- 如果直接将数据复制到分区目录下,select没有数据的话,可以执行`msck repair table order_table_s` 重新同步hdfs上的分区信息。
1.1.2、多个分区
-- 建表:两个分区
create table order_table_d
(
order_id int, -- 订单id
product_name string, -- 产品名称
price int -- 产品价格
)
partitioned by (deal_day string,category string) -- 交易日期YYYYMM,产品类别
row format delimited
fields terminated by "\t";
-- 查看表结构
hive> desc order_table_d;
OK
order_id int
product_name string
price int
deal_day string
category string
# Partition Information
# col_name data_type comment
deal_day string
category string
-- 源数据
-- order-201901-electronicproducts.txt
1 cellphone 2000
2 tv 3000
-- order-201901-car.txt
1 bicycle 1000
2 truck 20000
-- order-201902-fruit.txt
1 apple 10
2 banana 8
-- order-201902-drinks.txt
1 milk 70
2 liquor 150
-- 导入数据
load data local inpath '/root/data/order-201901-electronicproducts.txt' overwrite into table order_table_d partition(deal_day='201901',category='electronicproducts');
load data local inpath '/root/data/order-201901-car.txt' overwrite into table order_table_d partition(deal_day='201901',category='car');
load data local inpath '/root/data/order-201902-fruit.txt' overwrite into table order_table_d partition(deal_day='201902',category='fruit');
load data local inpath '/root/data/order-201902-drinks.txt' overwrite into table order_table_d partition(deal_day='201902',category='drinks');
-- 查看
hive> select * from order_table_d;
OK
1 bicycle 1000 201901 car
2 truck 20000 201901 car
1 cellphone 2000 201901 electronicproducts
2 tv 3000 201901 electronicproducts
1 milk 70 201902 drinks
2 liquor 150 201902 drinks
1 apple 10 201902 fruit
2 banana 8 201902 fruit
hive> show partitions order_table_d;
OK
deal_day=201901/category=car
deal_day=201901/category=electronicproducts
deal_day=201902/category=drinks
deal_day=201902/category=fruit
-- 查看hdfs目录
[root@zgg data]# hadoop fs -ls /user/hive/warehouse/order_table_d
Found 2 items
drwxr-xr-x - root supergroup 0 2021-01-08 17:00 /user/hive/warehouse/order_table_d/deal_day=201901
drwxr-xr-x - root supergroup 0 2021-01-08 17:00 /user/hive/warehouse/order_table_d/deal_day=201902
[root@zgg data]# hadoop fs -ls /user/hive/warehouse/order_table_d/deal_day=201901
Found 2 items
drwxr-xr-x - root supergroup 0 2021-01-08 17:00 /user/hive/warehouse/order_table_d/deal_day=201901/category=car
drwxr-xr-x - root supergroup 0 2021-01-08 17:00 /user/hive/warehouse/order_table_d/deal_day=201901/category=electronicproducts
-- 查看mysql中的元数据
mysql> select * from PARTITION_KEY_VALS;
+---------+--------------------+-------------+
| PART_ID | PART_KEY_VAL | INTEGER_IDX |
+---------+--------------------+-------------+
| 23 | 201901 | 0 |
| 23 | electronicproducts | 1 |
| 24 | 201901 | 0 |
| 24 | car | 1 |
| 25 | 201902 | 0 |
| 25 | fruit | 1 |
| 26 | 201902 | 0 |
| 26 | drinks | 1 |
+---------+--------------------+-------------+
-- 删除分区deal_day=201902/category=fruit
hive> alter table order_table_d drop partition(deal_day='201902',category='fruit');
-- 删除后,查看表分区
hive> show partitions order_table_d;
OK
deal_day=201901/category=car
deal_day=201901/category=electronicproducts
deal_day=201902/category=drinks
-- 删除后,查看hdfs目录
[root@zgg data]# hadoop fs -ls /user/hive/warehouse/order_table_d/deal_day=201902
Found 1 items
drwxr-xr-x - root supergroup 0 2021-01-08 17:00 /user/hive/warehouse/order_table_d/deal_day=201902/category=drinks
-- 删除后,查看mysql中的元数据
mysql> select * from PARTITION_KEY_VALS;
+---------+--------------------+-------------+
| PART_ID | PART_KEY_VAL | INTEGER_IDX |
+---------+--------------------+-------------+
| 23 | 201901 | 0 |
| 23 | electronicproducts | 1 |
| 24 | 201901 | 0 |
| 24 | car | 1 |
| 26 | 201902 | 0 |
| 26 | drinks | 1 |
+---------+--------------------+-------------+
-- 重新添加分区deal_day=201902/category=fruit
hive> alter table order_table_d add partition(deal_day='201902',category='fruit');
-- 重新导入
hive> load data local inpath '/root/data/order-201902-drinks.txt' overwrite into table order_table_d partition(deal_day='201902',category='drinks');
-- 查看
hive> select * from order_table_d;
1 bicycle 1000 201901 car
2 truck 20000 201901 car
1 cellphone 2000 201901 electronicproducts
2 tv 3000 201901 electronicproducts
1 milk 70 201902 drinks
2 liquor 150 201902 drinks
hive> show partitions order_table_d;
deal_day=201901/category=car
deal_day=201901/category=electronicproducts
deal_day=201902/category=drinks
deal_day=201902/category=fruit
-- 导入数据到分区表,还可以使用 insert
-- 将order_table_d的201901分区中的数据插入到order_table_s的201901分区中
-- 查看order_table_s数据
hive> select * from order_table_s;
1 apple 10 201902
2 banana 8 201902
3 milk 70 201902
4 liquor 150 201902
hive> insert into table order_table_s partition(deal_day='201901') select order_id,product_name,price from order_table_d where deal_day='201901';
-- 查看结果
hive> select * from order_table_s where deal_day='201901';
1 bicycle 1000 201901
2 truck 20000 201901
1 cellphone 2000 201901
2 tv 3000 201901
1.2、动态分区
上面展示了如何使用 insert 插入到分区表,如果再插入分区 ‘201902’ 数据,需要再写一条 insert 语句。
而动态分区可以直接使用一条 insert 语句完成。
下面利用动态分区进行演示。
演示前先进行设置:
hive 中默认是静态分区,想要使用动态分区,需要设置如下参数,可以使用临时设置,也可以写在配置文件(hive-site.xml)里,永久生效。临时配置如下:
//开启动态分区 默认为false,不开启
set hive.exec.dynamic.partition=true;
//指定动态分区模式,默认为strict,即必须指定至少一个分区为静态分区,
//nonstrict模式表示允许所有的分区字段都可以使用动态分区
set hive.exec.dynamic.partition.mode=nonstrict;
-- 创建动态分区表
create table order_table_dy
(
order_id int, -- 订单id
product_name string, -- 产品名称
price int -- 产品价格
)
partitioned by (deal_day string) -- 交易日期YYYYMM,产品类别
row format delimited
fields terminated by "\t";
hive> select * from order_table_s;
1 bicycle 1000 201901
2 truck 20000 201901
1 cellphone 2000 201901
2 tv 3000 201901
1 apple 10 201902
2 banana 8 201902
3 milk 70 201902
4 liquor 150 201902
-- 将order_table_s表里的两个分区的数据插入到order_table_dy表
hive> insert into table order_table_dy(deal_day) select order_id,product_name,price,deal_day from order_table_s;
-- 查看结果
hive> select * from order_table_dy where deal_day=201901;
OK
1 bicycle 1000 201901
2 truck 20000 201901
1 cellphone 2000 201901
2 tv 3000 201901
hive> select * from order_table_dy where deal_day=201902;
OK
1 apple 10 201902
2 banana 8 201902
3 milk 70 201902
4 liquor 150 201902
hive> show partitions order_table_dy;
OK
deal_day=201901
deal_day=201902
静态分区(SP)列:在涉及多个分区列的 DML/DDL 中,这些列的值在编译时已知(由用户给出)。
动态分区(DP)列:在执行时才知道其值的列。
DP 列的指定方式与 SP 列的指定方式相同:在 partition 子句中。唯一的区别是 DP 列没有值,而 SP 列有。在 partition 子句中,我们需要指定所有分区列,即使它们都是 DP 列。
在 INSERT ... SELECT ...
查询时,动态分区列必须在 SELECT 语句中的最后一个列中指定,且顺序与它们在 PARTITION() 子句中出现的顺序相同。
-- 正确
INSERT OVERWRITE TABLE T PARTITION (ds='2010-03-03', hr)
SELECT key, value, /*ds,*/ hr FROM srcpart WHERE ds is not null and hr>10;
-- 错误
INSERT OVERWRITE TABLE T PARTITION (ds, hr = 11)
SELECT key, value, ds/*, hr*/ FROM srcpart WHERE ds is not null and hr=11;
2、分桶
通过计算表的某些列的哈希值,分区中的数据再被划分到桶中。
例如,page_views 表根据 userid 分桶,userid 是 page_view 表的列之一,而不是分区列。
将表或分区组织成桶有以下几个目的:
(1)抽样更高效,因为在处理大规模的数据集时,在开发、测试阶段将所有的数据全部处理一遍可能不太现实,这时抽样就必不可少。
抽样:
SELECT * FROM table_name TABLESAMPLE(n PERCENT);
抽样出n%的数据,会全表扫描。
有了桶之后呢?
如果在 TABLESAMPLE 子句中指定的列与 CLUSTERED BY 子句中的列相匹配,则 TABLESAMPLE 只扫描表中要求的哈希分区【就是具体的桶】
SELECT * FROM film TABLESAMPLE(BUCKET x OUTOF y)
如果表是用 `CLUSTERED BY id INTO 32 BUCKETS` 创建的。
TABLESAMPLE(BUCKET 3 OUT OF 16 ON id):
将挑选出第 3 和第 19 个聚类,因为每个桶将由 (32/16)=2 个聚类组成。
【每个桶有2个聚类,一共64个聚类,取出第 3 和第 19 个聚类】
TABLESAMPLE(BUCKET 3 OUT OF 64 ON id):
将挑选出第 3 个聚类的一半,因为每个桶将由 (32/64)=1/2 个聚类组成
(2)更好的查询处理效率。
大表在JOIN的时候,效率低下。如果对两个表先分别按id分桶,那么相同id都会归入一个桶。
那么此时再进行JOIN的时候是按照桶来JOIN的,那么大大减少了JOIN的数量。
在建立桶之前,需要设置 set hive.enforce.bucketing=true;
,使得 hive 能识别桶。【仅版本 0.x 和 1.x,对于2.x版本不再需要】
hive> select * from order_table_s;
OK
1 bicycle 1000 201901
2 truck 20000 201901
1 cellphone 2000 201901
2 tv 3000 201901
1 apple 10 201902
2 banana 8 201902
3 milk 70 201902
4 liquor 150 201902
-- 创建分桶
create table order_table_buckets
(
order_id int, -- 订单id
product_name string, -- 产品名称
price int -- 产品价格
)
partitioned by (deal_day string) -- 交易日期YYYYMM,产品类别
clustered by (order_id) into 4 buckets
row format delimited
fields terminated by "\t";
-- 导入数据:
hive> insert into table order_table_buckets partition(deal_day) select order_id,product_name,price,deal_day from order_table_s where order_id=1;
-- 查看表
hive> select * from order_table_buckets;
OK
1 cellphone 2000 201901
1 bicycle 1000 201901
1 apple 10 201902
-- 查看hdfs中的目录
[root@zgg ~]# hadoop fs -ls /user/hive/warehouse/order_table_buckets
Found 2 items
drwxr-xr-x - root supergroup 0 2021-01-08 18:49 /user/hive/warehouse/order_table_buckets/deal_day=201901
drwxr-xr-x - root supergroup 0 2021-01-08 18:49 /user/hive/warehouse/order_table_buckets/deal_day=201902
[root@zgg ~]# hadoop fs -ls /user/hive/warehouse/order_table_buckets/deal_day=201901
Found 4 items
-rw-r--r-- 1 root supergroup 0 2021-01-08 18:49 /user/hive/warehouse/order_table_buckets/deal_day=201901/000000_0
-rw-r--r-- 1 root supergroup 32 2021-01-08 18:49 /user/hive/warehouse/order_table_buckets/deal_day=201901/000001_0
-rw-r--r-- 1 root supergroup 0 2021-01-08 18:49 /user/hive/warehouse/order_table_buckets/deal_day=201901/000002_0
-rw-r--r-- 1 root supergroup 0 2021-01-08 18:49 /user/hive/warehouse/order_table_buckets/deal_day=201901/000003_0
参考: