内部表、外部表、分区表、分桶表

一、内部表

内部表也称为管理表,默认创建的表都是内部表。因为这种表,Hive 会(或多或少地)控制着数据的生命周期。Hive 默认情况下会将这些表的数据存储在由配置项hive.metastore.warehouse.dir(例如,/user/hive/warehouse)所定义的目录的子目录下。当我们删除一个内部表时,Hive也会删除这个表中数据。内部表不适合和其它工具共享数据。

create table if not exists default.dept( 
  deptno int, 
  dname string, 
  loc int) 
  row format delimited fields terminated by '\t';

以上语句就会创建一个内部表。

二、外部表

外部表和内部表是对应的,顾名思义,外部表不是其所管理数据的唯一拥有者,所以当删除外部表的时候只会删除Hive中的元数据而不会删除实际数据。如果某一数据集被多个项目或者业务所使用,就需要使用外部表。

外部表就是在创建的时候加上 external 关键字,如:

create external table if not exists default.dept(
  deptno int,
  dname string,
  loc int)
  row format delimited fields terminated by '\t';

如果要查看某一张表是内部表(管理表)还是外部表,需要执行 desc formatted 表名字,如:desc formatted student;。如果看到输出的 Table Type 是 MANAGED_TABLE 则说明是内部表,如果是 EXTERNAL_TABLE 则说明是外部表。

如果要将内部表转换为外部表,需要执行:

alter table student set tblproperties('EXTERNAL'='TRUE');

如果要将外部表转换为内部表,需要执行:

alter table student set tblproperties('EXTERNAL'='FALSE');

注意:(‘EXTERNAL’=’TRUE’)和(‘EXTERNAL’=’FALSE’)为固定写法,区分大小写!

三、分区表

Hive中的表其实对应的就是HDFS中的某个文件夹目录,在执行查询的时候也会暴力扫描整个文件夹,但是如果在该表所对应的文件夹下面增加一些特殊含义的子文件夹,并使这些子文件夹可以当做 where 查询条件来使用,那么则可以大大提升查询的性能。

分区表实际上就是对应一个 HDFS 文件系统上的独立的文件夹,该文件夹下是该分区所有的数据文件。Hive 中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据集(在HDFS中的提现就是多个子目录)。在查询时通过 where 子句中的表达式选择查询所需要的指定的分区,这样的查询效率会提高很多。

3.1 创建分区表

以下语句就会创建一个分区表:

create table dept_partition(
  deptno int, dname string, loc string)
  partitioned by (month string)
  row format delimited fields terminated by '\t';

注意:在创建分区表的时候是通过 partitioned by 字段来指定分区键的,而且该键也是 dept_partition 表中的一个字段(所以以上语句创建的表应该包含 depno、dname、loc、month 四个字段)。

紧接着,我们分别执行以下三条语句向该表中导入数据:

load data local inpath '/opt/module/datas/dept.txt' into table default.dept_partition partition(month='201709');

load data local inpath '/opt/module/datas/dept.txt' into table default.dept_partition partition(month='201708');

load data local inpath '/opt/module/datas/dept.txt' into table default.dept_partition partition(month='201707’);

数据导入成功以后在HDFS上提现出来的是不同的文件夹,每个文件夹下面都会有一个 dept.txt 文件。

注意:分区表在导入数据的时候如果不通过 partition 指定分区会报错。像这样:FAILED: SemanticException [Error 10062]: Need to specify partition columns because the destination table is partitioned

分区表的分区字段也可以有多个,如:

create table dept_partition2(
  deptno int, 
  dname string, 
  loc string)
  partitioned by (month string, day string)
  row format delimited fields terminated by '\t';

以上语句会创建一个具有两个分区字段(month、day)的分区表,在HDFS上体现为 month 目录下会有 day 的子目录。所以同理,在导入数据的时候也需要指定两个分区字段。

3.2 增加分区

增加单个分区:

alter table dept_partition add partition(month='201706') ;

增加多个分区:

alter table dept_partition add partition(month='201704') partition(month='201705') ;

3.3 删除分区

删除单个分区

alter table dept_partition drop partition(month='201704') ;

删除多个分区

alter table dept_partition drop partition(month='201705') , partition(month='201706') ;

3.4 把数据直接上传到分区目录上,让分区表和数据产生关联的三种方式

(1)方式一:上传数据后修复

上传数据

dfs -mkdir -p /user/hive/warehouse/dept_partition/month=201710;

dfs -put /opt/module/data/dept.txt /user/hive/warehouse/dept_partition/month=201710;

此时我们直接查询的话是查询不到数据的 month=201710下面的数据的,

执行修复命令 msck repair table dept_partition; 之后再次查询就会看到数据。

 

(2)方式二:上传数据后添加分区

上传数据

dfs -mkdir -p /user/hive/warehouse/dept_partition/month=201711 ;

dfs -put /opt/module/data/dept.txt /user/hive/warehouse/dept_partition/month=201711 ;

此时我们直接查询的话是查询不到数据的 month=201711下面的数据的,

执行添加分区命令 alter table dept_partition add partition(month='201711'); 之后再次查询就会看到数据。

 

(3)方式三:创建文件夹后 load 数据到分区

创建目录并 load 数据

dfs -mkdir -p /user/hive/warehouse/dept_partition/month=201712 ;

load data local inpath '/opt/module/data/dept.txt' into table dept_partition partition(month='201712') ;

 

注意:以上三种方式是将数据上传到一个新的分区目录中,所以一开始查询不到数据,需要修复或者执行 alter 操作,但是如果将数据直接上传到已经存在的分区目录中(如:month=201709),是可以直接查询到数据的。

四、分桶表

分区针对的是数据的存储路径(文件夹);分桶针对的是数据文件本身。

分区是按照文件夹的方式对数据进行隔离区分,但是并非所有的数据集都适合按照字段分区,而且如果分区字段太多的话会造成大量子文件夹,有可能部分文件夹是空的,而且大量的文件夹对于文件系统维护来说也不是好事。

而分桶是将数据集放在同一个文件夹下面,但是会放在不同的文件里面,跟 MapReduce 的分区比较像。根据数据的某个字段的 Hash 去决定将数据放到哪个文件中,分桶的使用没有分区那么普遍,只有在数据量极大的时候才会使用。

创建分桶表,将该表分成4个桶:

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

在Hive 2.x以前的版本中还需要执行以下命令设置强制分桶才会生效,但是在2.x以后的版本不需要。

set hive.enforce.bucketing=true;
set mapreduce.job.reduces=-1;

 

 

点个赞呗:程序员虾说 » 内部表、外部表、分区表、分桶表

赞 (0) 打赏

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

请作者喝杯咖啡~

支付宝扫一扫打赏

微信扫一扫打赏