Hive学习笔记:表的类型、视图、索引以及加载方式
Hive表的类型
Hive 的表有哪些类型呢,我们简单可以分为四种,受控表、外部表、分区表、桶表,从严格意义上说,应该分为两种受控表,又叫内部表、外部表,分区表和桶表其实是受控表的不同体现。
1、受控表
所谓受控表,我们也经常叫内部表,和外部表对应起来,就是说表的数据的生命周期收表的控制,当表定义被删除的时候,表中的数据随之一并被删除。创建一张表,其对应在hive中就有了表记录,在metastore表TBLS中就有表定义,当我们一旦从hive中删除一张表的定义之后,其表中的数据也就不复存在了,在metastore中的定义也就不存在了。
2、外部表
和受控表相对的,怎么相对呢,你的内部表的数据的生命周期受表定义的影响不是,外部表的不是这样的,数据的生命周期, 或者说数据存在与否和表的定义互不约束,表中的数据呢,只是表对hdfs上相应文件的一个引用而已,当删除表定义的时候,表中的数据依然存在。
如何创建外部表?
create external table tblName(colName colType...);
external,是外部表,必须要和内部表区别一下
加载数据
alter table tblName set location 'hdfs_absolute_uri';
一个是location,不是引用hdfs的数据吗,
当然在创建表的时候就可以告诉它引用数据的地方
create external table tblName(colName colType...) location 'hdfs_absolute_uri';
3、分区表
假设服务器集群每天都产生一个日志数据文件,把数据文件统一存储到HDFS中。我们如果想查询某一天的数据的话,hive执行的时候会对所有文件都扫描一遍,判断是否是指定的日期。可以让日期作为一个子目录。当hive查询的时候,根据日期去判断子目录。然后扫描符合条件的子目录中的数据文件。
如何创建一张分区表?
只需要在之前的创建表后面加上分区字段就可以了,
create table tblName (
id int comment 'ID',
name string comment 'name'
) partitioned by (dt date comment 'create time')
row format delimited
fields terminated by '\t';
如何加载数据?
load data local inpath linux_fs_path into table tblName partition(dt='2015-12-12');
上面的语句会在hive表tblName中自动创建一个分区,以dt='2015-12-12'为文件夹名称,下面存放上传的数据
相应的在metastore中的partitions中就有了相应的记录。
分区的一些操作:
查询分区中的数据:select * from tblName where dt='2015-12-13';(分区相当于where的一个条件)
手动创建一个分区:alter table tblName add partition(dt='2015-12-13');
查看分区表有哪些分区:show partitions tblName;
删除一个分区:alter table tblName drop partition(dt='2015-12-12');
多个分区如何创建?和单分区表的创建类似:
create table tblName (
id int comment 'ID',
name string comment 'name'
) partitioned by (year int comment 'admission year', school string comment 'school name')
row format delimited
fields terminated by '\t';
同时也可以从hdfs上引用数据:
alter table tblName partition(year='2015', school='crxy') set location hdfs_uri;
注意:
必须得现有分区,必须要使用hdfs绝对路径
相应的分区下面没有数据对吧,你删了分区也不会影响原来的数据对不对,有点动态引用的意思。
删除分区:
alter table tmp_h02_click_log_baitiao drop partition(dt=‘2014-03-01’);
4、桶表
桶表是对数据进行哈希取值,然后放到不同文件中存储。分桶是将数据及分解成更容易管理的若干部分的另一种技术。如果进行表连接操作,那么就需要对两张表的数据进行全扫描。非常耗费时间。可以针对连接字段进行优化。分桶这种情况下呢,对于相似的表中的数据进行比较的话就非常的方便了,只要对比相应的桶中的数据就可了。
如何创建桶表?
create table tblName_bucket(id int) clustered by (id) into 3 buckets;
说明:
clustered by :按照什么分桶
into x buckets:分成x个桶
如何加载数据?
不能使用load data这种方式,需要从别的表来引用
insert into table tblName_bucket select * from tbl_other;
注意:在插入数据之前需要先设置开启桶操作,不然插入数据不会设置为桶!!!
set hive.enforce.bucketing=true;
桶表的主要作用:
数据抽样
提高某些查询效率
Hive视图
Hive中,也有视图的概念,那我们都知道视图实际上是一张虚拟的表,是对数据的逻辑表示,只是一种显示的方式,主要的作用呢:
1、视图能够简化用户的操作
2、视图使用户能以多钟角度看待同一数据
3、视图对重构数据库提供了一定程度的逻辑独立性
4、视图能够对机密数据提供安全保护
5、适当的利用视图可以更清晰的表达查询
那我们在Hive中如何来创建一个视图呢?
create view t_view as select * from otherTbl;
关于视图的几点说明:
1、只有视图的定义,没有相应的物理结构
也就是说只有在metastore中有和hdfs中的映射关系,在hdfs中没有相应的文件夹
2、操作
可以把视图当做表的一个衍伸,所以对hive表的各种操作,在视图上就有。
hive索引
索引是标准的数据库技术,hive 0.7版本之后支持索引。Hive提供有限的索引功能,这不像传统的关系型数据库那样有“键(key)”的概念,用户可以在某些列上创建索引来加速某些操作,给一个表创建的索引数据被保存在另外的表中。 Hive的索引功能现在还相对较晚,提供的选项还较少。但是,索引被设计为可使用内置的可插拔的java代码来定制,用户可以扩展这个功能来满足自己的需求。 当然不是说有的查询都会受惠于Hive索引。用户可以使用EXPLAIN语法来分析HiveQL语句是否可以使用索引来提升用户查询的性能。像RDBMS中的索引一样,需要评估索引创建的是否合理,毕竟,索引需要更多的磁盘空间,并且创建维护索引也会有一定的代价。 用户必须要权衡从索引得到的好处和代价。
创建索引
create index t1_index on table t1(stu_name) as
'org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler'
with deferred rebuild in table t1_index_table;
重建索引
alter index t1_index on t1 rebuild;
显示索引
show formatted index on t1;
删除索引
drop index if exists t1_index on t1;
Hive数据加载方式
说明:[]表示可有可无,<>表示必须要有
1°、从linux fs和hdfs中加载
load data [local] inpath 'path' [overwrite] into table tblName [partition_sepc];
几个关键字有无的说明:
local:
有:数据从本地path中加载,其中path可以是绝对路径,也可以是相对路径。
无:数据从hdfs上的相应路径path中移动数据到表tblName下,相当于hadoop fs -mv hdfs_uri_1 hdfs_uri_2
overwrite:
有:覆盖原来的数据,只保留新上传的数据。
无:在原来的目录下,在增加一个数据文件。
partition:
有:增加到相应的分区中
无:该表不是分区表
2°、从其他表中装载
insert <into|overwrite> table tblName select columns... from otherTblName;
关于overwrite的含义和上述是一致的。
唯一一点需要说明的是:
tblName表中的字段要和后面select查询的字段要保持一致!!!
3°、通过动态分区装载数据
如果我们表的分区创建非常多的话,对于我们装载数据是一件非常麻烦的事,Hive提供动态分区来解决这个问题。可以基于查询参数推断出需要创建的分区名称,相比的分区都是静态的,这里就称之为动态的分区。
怎么来弄呢?
INSERT overwrite TABLE t3 PARTITION(province='gs', city)
SELECT t.province, t.city FROM temp t WHERE t.province='gs';
说明一下:静态分区必须出现在动态分区之前!!!
我想连province='gs'都省了?
报错了,需要我们开启动态分区的支持
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nostrict;
set hive.exec.max.dynamic.partitions.pernode=1000;
INSERT overwrite TABLE t3 PARTITION(province, city)
SELECT t.province, t.city FROM temp t;
经验说明一点:在创建分区的时候,最好不要创建过多的分区,如果分区过多的话,查询也是非常的慢的,就像在window下一个文件夹下面的文件过多会对我们的使用造成非常的不便的。那么hive能支持多大的分区数呢,可以使用命令
set hive.exec.max.dynamic.partitions获取
4、创建表的同时装载数据
和之前创建视图的时候的语法非常相似,把view改成table就可以
create table newTblName as select columns from other_tblName;
Hive数据的导出
这个是数据装载的反向过程,有两种方式
1°、在hdfs的直接上操作
hadoop fs -cp src_uri dest_uri
2°、在终端使用directory
insert overwrite [local] directory 'linux_fs_path' select ...from... where ...;
Hive本地模式
之前有些hql语句的执行最后转化为了mr,但是执行的过程非常的慢,如何提高执行效率呢?使用本地模式。
需要开启本地模式:
set hive.exec.mode.local.auto=true;
再去执行相同的hql时,会发现速度提高很多。但是,本地模式主要用来做调试,不能配置到hive-site.xml中,因为本地模式,会只在当前机器上执行mr,但是如果数据量一大,这样会累垮我们的单台节点的。