Hive:分区

Hive分区的概念与传统关系型数据库分区不同。

传统数据库的分区方式:就oracle而言,分区独立存在于段里,里面存储真实的数据,在数据进行插入的时候自动分配分区。

Hive的分区方式:由于Hive实际是存储在HDFS上的抽象,Hive的一个分区名对应一个目录名,子分区名就是子目录名,并不是一个实际字段。

静态分区

一级分区

创建

Hive分区是在创建表的时候用Partitioned by 关键字定义的,但要注意,Partitioned by子句中定义的列是表中正式的列,但是Hive下的数据文件中并不包含这些列,因为它们是目录名。注意:分区字段不能和表中的字段重复。

1
2
3
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
一级分区:一个目录
多级分区:多个目录
1
2
3
4
5
6
7
8
9
10
CREATE TABLE `emp_partition`(
`empno` int,
`ename` string,
`job` string,
`mgr` int,
`hiredate` string,
`sal` double,
`comm` double
) partitioned by (deptno string)
row format delimited fields terminated by '\t';

通过desc查看的表结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
hive (hive)> desc emp_partition;
OK
col_name data_type comment
empno int
ename string
job string
mgr int
hiredate string
sal double
comm double
deptno string

# Partition Information
# col_name data_type comment
deptno string
Time taken: 0.546 seconds, Fetched: 12 row(s)

插入数据

1
2
3
4
格式1:
INSERT INTO TABLE tablename [PARTITION (partcol1[=val1], partcol2[=val2] ...)] VALUES values_row [, values_row …];
格式2:
load data local inpath '/home/hadoop/data/emp_10.txt' into table emp_partition partition (deptno=10);

从其他表中插入数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
hive (hive)> select * from emp;
OK
emp.empno emp.ename emp.job emp.mgr emp.hiredate emp.sal emp.comm emp.deptno
7369 SMITH CLERK 7902 1980-12-17 800.0 NULL 20
7499 ALLEN SALESMAN 7698 1981-2-20 1600.0 300.0 30
7521 WARD SALESMAN 7698 1981-2-22 1250.0 500.0 30
7566 JONES MANAGER 7839 1981-4-2 2975.0 NULL 20
7654 MARTIN SALESMAN 7698 1981-9-28 1250.0 1400.0 30
7698 BLAKE MANAGER 7839 1981-5-1 2850.0 NULL 30
7782 CLARK MANAGER 7839 1981-6-9 2450.0 NULL 10
7788 SCOTT ANALYST 7566 1987-4-19 3000.0 NULL 20
7839 KING PRESIDENT NULL 1981-11-17 5000.0 NULL 10
7844 TURNER SALESMAN 7698 1981-9-8 1500.0 0.0 30
7876 ADAMS CLERK 7788 1987-5-23 1100.0 NULL 20
7900 JAMES CLERK 7698 1981-12-3 950.0 NULL 30
7902 FORD ANALYST 7566 1981-12-3 3000.0 NULL 20
7934 MILLER CLERK 7782 1982-1-23 1300.0 NULL 10
Time taken: 0.269 seconds, Fetched: 14 row(s)
hive (hive)> insert into emp_partition partition(deptno=30) select empno,ename,job,mgr,hiredate,sal,comm from emp where deptno=10;

从文件加载数据到表中(不包含分区列字段)

1
2
[hadoop@hadoop001 data]$ cat emp_10.txt 
88 KK SALESMAN 8888 1998-10-14 5000 500
1
hive (hive)> load data local inpath '/home/hadoop/data/emp_10.txt' into table emp_partition partition (deptno=10);

查看数据

利用分区表查询:(一般分区表都是利用where语句查询的)

1
2
3
4
5
6
7
8
hive (hive)> select * from emp_partition where deptno=10;
OK
emp_partition.empno emp_partition.ename emp_partition.job emp_partition.mgr emp_partition.hiredate emp_partition.sal emp_partition.comm emp_partition.deptno
7782 CLARK MANAGER 7839 1981-6-9 2450.0 NULL 10
7839 KING PRESIDENT NULL 1981-11-17 5000.0 NULL 10
7934 MILLER CLERK 7782 1982-1-23 1300.0 NULL 10
88 KK SALESMAN 8888 1998-10-14 5000.0 500.0 10
Time taken: 0.25 seconds, Fetched: 4 row(s)

查看hdfs上emp_partition表目录结构,可以看到在以表名目录下,有以deptno=10(分区名)的子目录存放着真实的数据文件

1
2
3
[hadoop@hadoop001 data]$ hadoop fs -ls -R /user/hive/warehouse/hive.db/emp_partition
drwxr-xr-x - hadoop supergroup 0 2021-12-28 14:01 /user/hive/warehouse/hive.db/emp_partition/deptno=10
-rw-r--r-- 1 hadoop supergroup 130 2021-12-28 14:01 /user/hive/warehouse/hive.db/emp_partition/deptno=10/000000_0

同理,插入deptno为20,30的数据。

1
2
3
4
5
6
7
8
[hadoop@hadoop001 data]$ hadoop fs -ls -R /user/hive/warehouse/hive.db/emp_partition
drwxr-xr-x - hadoop supergroup 0 2021-12-28 12:12 /user/hive/warehouse/hive.db/emp_partition/deptno=10
-rw-r--r-- 1 hadoop supergroup 130 2021-12-28 14:01 /user/hive/warehouse/hive.db/emp_partition/deptno=10/000000_0
-rw-r--r-- 1 hadoop supergroup 40 2021-12-28 12:12 /user/hive/warehouse/hive.db/emp_partition/deptno=10/emp_10.txt
drwxr-xr-x - hadoop supergroup 0 2021-12-28 14:01 /user/hive/warehouse/hive.db/emp_partition/deptno=20
-rw-r--r-- 1 hadoop supergroup 214 2021-12-28 14:01 /user/hive/warehouse/hive.db/emp_partition/deptno=20/000000_0
drwxr-xr-x - hadoop supergroup 0 2021-12-28 12:11 /user/hive/warehouse/hive.db/emp_partition/deptno=30
-rw-r--r-- 1 hadoop supergroup 40 2021-12-28 12:11 /user/hive/warehouse/hive.db/emp_partition/deptno=30/000000_0

查看分区

1
2
3
4
5
6
7
hive (hive)> show partitions emp_partition;
OK
partition
deptno=10
deptno=20
deptno=30
Time taken: 0.152 seconds, Fetched: 3 row(s)

添加分区

1
2
3
4
5
6
7
8
9
10
11
hive (hive)> alter table emp_partition  add partition (deptno=40);
OK
Time taken: 0.282 seconds
hive (hive)> show partitions emp_partition;
OK
partition
deptno=10
deptno=20
deptno=30
deptno=40
Time taken: 0.127 seconds, Fetched: 4 row(s)

删除分区(删除相应分区文件)

注意,对于外表进行drop partition并不会删除hdfs上的文件,并且可以通过msck repair table table_name同步hdfs上的分区。

1
alter table emp_partition drop partition (deptno = 40);

修复分区

修复分区就是重新同步hdfs上的分区信息。(外部表在hdfs目录上添加文件后使用)

1
msck repair table table_name  [ADD/DROP/SYNC PARTITIONS];

在hive3.0中msck命令支持删除partition信息。

多级分区

多分区表装载数据时,分区字段必须都要加。如果只有一个,会报错。

下面创建一张静态分区表par_tab_muilt,多个分区(性别+日期)

1
2
hive (hive)> create table par_tab_muilt (name string, nation string) partitioned by (sex string,dt string) row format delimited fields terminated by ',' ;
hive (hive)> load data local inpath '/home/hadoop/files/par_tab.txt' into table par_tab_muilt partition (sex='man',dt='2021-12-28');
1
2
3
4
[hadoop@hadoop001 files]$ hadoop fs -ls -R /user/hive/warehouse/par_tab_muilt
drwxr-xr-x - hadoop supergroup 0 2021-12-28 08:45 /user/hive/warehouse/par_tab_muilt/sex=man
drwxr-xr-x - hadoop supergroup 0 2021-12-28 08:45 /user/hive/warehouse/par_tab_muilt/sex=man/dt=2021-12-28
-rwxr-xr-x 1 hadoop supergroup 71 2021-12-28 08:45 /user/hive/warehouse/par_tab_muilt/sex=man/dt=2021-12-28/par_tab.txt

可见,新建表的时候定义的分区顺序,决定了文件目录顺序(谁是父目录谁是子目录),正因为有了这个层级关系,当我们查询所有man的时候,man以下的所有日期下的数据都会被查出来。如果只查询日期分区,但父目录sex=man和sex=woman都有该日期的数据,那么Hive会对输入路径进行修剪,从而只扫描日期分区,性别分区不作过滤(即查询结果包含了所有性别)。

动态分区

为什么要使用动态分区呢,我们举个例子,假如中国有50个省,每个省有50个市,每个市都有100个区,那我们都要使用静态分区要使用多久才能搞完。所有我们要使用动态分区。

注意,动态分区不允许主分区采用动态列而副分区采用静态列,这样将导致所有的主分区都要创建副分区静态列所定义的分区。

动态分区可以允许所有的分区列都是动态分区列,但是要首先设置一个参数hive.exec.dynamic.partition.mode

动态分区默认是没有开启。开启后默认是以严格模式执行的,在这种模式下需要至少一个分区字段是静态的。这是为了防止用户有可能原意是只在子分区内进行动态建分区,但是由于疏忽忘记为主分区列指定值了,这将导致一个dml语句在短时间内创建大量的新的分区(对应大量新的文件夹),对系统性能带来影响。这有助于阻止因设计错误导致导致查询差生大量的分区。列如:用户可能错误使用时间戳作为分区表字段。然后导致每秒都对应一个分区!这样我们也可以采用相应的措施:

1
2
关闭严格分区模式		set hive.exec.dynamic.partition.mode=nonstrict	//分区模式,默认strict(至少有一个分区列是静态分区)
开启支持动态分区 set hive.exec.dynamic.partition=true //开启动态分区,默认true
1
2
3
4
其他相关参数 :
set hive.exec.max.dynamic.partitions.pernode; #每一个执行mr节点上,允许创建的动态分区的最大数量(100)
set hive.exec.max.dynamic.partitions; #所有执行mr节点上,允许创建的所有动态分区的最大数量(1000)
set hive.exec.max.created.files; #所有的mr job允许创建的文件的最大数量(100000)

利用动态分区,我们可以一次完成插入上面例子中deptno不同的数据的操作

1
insert overwrite table emp_partition partition(deptno) select empno,ename,job,mgr,hiredate,sal,comm,deptno from emp;

补充

注意事项

  1. hive的分区使用的表外字段,分区字段是一个伪列但是可以查询过滤。
  2. 分区字段不建议使用中文.
  3. 不太建议使用动态分区。因为动态分区将会使用mapreduce来查询数据,如果分区数量过多将导致namenode和yarn的资源瓶颈。所以建议动态分区前也尽可能之前预知分区数量。
  4. 分区属性的修改均可以使用手动元数据和hdfs的数据内容

外部分区表

外部表同样可以使用分区,事实上,用户会发现,只是管理大型生产数据集最常见的情况,这种结合给用户提供一个和其他工具共享数据的方式,同时也可以优化查询性能。这样我们就可以把数据路径改变而不影响数据的丢失,这是内部分区表远远不能做的事情:

1
2
3
4
5
6
7
8
9
10
11
12
1,(因为我们创建的是外部表)所有我们可以把表数据放到hdfs上的随便一个地方这里自动数据加载到/user/had/data/下(当然我们之前在外部表上指定了路径)
load data local inpath '/home/had/data.txt' into table employees_ex partition (country="china",state="Asia");
2,如果我们加载的数据要分离一些旧数据的时候就可以hadoop的distcp命令来copy数据到某个路径
hadoop distcp /user/had/data/country=china/state=Asia /user/had/data_old/country=china/state=Asia
3,修改表,把移走的数据的路径在hive里修改
alter table employees partition(country="china",state="Asia") set location '/user/had/data_old/country=china/state=Asia'
4,使用hdfs的rm命令删除之前路径的数据
hdfs dfs -rmr /user/had/data/country=china/state=Asia
这样我们就完成一次数据迁移

如果觉得突然忘记了数据的位置使用使用下面的方式查看
describe extend employees_ex partition (country="china",state="Asia");

众多的修改语句

1
2
3
4
5
6
7
8
9
10
11
1,把一个分区打包成一个har包
alter table employees archive partition (country="china",state="Asia")
2, 把一个分区har包还原成原来的分区
alter table employees unarchive partition (country="china",state="Asia")
3, 保护分区防止被删除
alter table employees partition (country="china",state="Asia") enable no_drop
4,保护分区防止被查询
alter table employees partition (country="china",state="Asia") enable offline
5,允许分区删除和查询
alter table employees partition (country="china",state="Asia") disable no_drop
alter table employees partition (country="china",state="Asia") disable offline

参考链接:

https://www.cnblogs.com/yongjian/archive/2017/03/29/6640951.html

https://blog.csdn.net/weixin_41122339/article/details/81584110

https://blog.csdn.net/lixinkuan328/article/details/102103237