Hive中支持的数据类型如下:
Hive中支持的数据类型比较多,其中红色是使用比较多的类型。
CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name
[(col_name data_type [COMMENT col_comment], ...)]
[COMMENT table_comment]
[PARTITIONED BY (col_name data_type [COMMENT col_comment], ...)]
[CLUSTERED BY (col_name, col_name, ...)]
[SORTED BY (col_name [ASC|DESC], ...)] INTO num_buckets BUCKETS]
[ROW FORMAT row_format]
[STORED AS file_format]
[LOCATION hdfs_path]
创建表关键字解释:
EXTERNAL
:创建外部表
PARTITIONED BY
:分区表
CLUSTERED BY
:分桶表
STORED AS
:存储格式
LOCATION
:存储位置
…
-- 简单表创建类似mysql中创建表:
CREATE TABLE test(
id INT,
name STRING,
gender STRING
);
DROP TABLE table_name;
未被external关
键字修饰的即是内部表, 即普通表。 内部表又称管理表,内部表数据存储的位置由hive.metastore.warehouse.dir参数决定(默认:/user/hive/warehouse)
,删除内部表会直接删除元数据(metadata)及存储数据
,因此内部表不适合和其他工具共享数据。
被external
关键字修饰的即是外部表。外部表是指表数据可以在任何位置,通过LOCATION关键字
指定。 数据存储的不同也代表了这个表在理念是并不是Hive内部管理的,而是可以随意临时链接到外部数据上的。所以,在删除外部表的时候, 仅仅是删除元数据(表的信息),不会删除数据本身
。
基础表创建:
-- 创建一个基础的内部表
create table if not exists stu(id int,name string);
创建表,默认的数据分隔符是\001
,是一种特殊字符,是ASCII
值,键盘是打不出来的,且在某些文本编辑器中的显示是为SOH
。
指定分隔符
-- 自行指定分隔符 '\t'
create table if not exists stu2(id int ,name string) row format delimited fields terminated by '\t';
row format delimited fields terminated by '\t'
:表示以\t
分隔
其他创建表形式:
-- 1. 基于查询结果建表,CREATE TABLE table_name as
create table stu3 as select * from stu2;
-- 2. 基于已存在的表结构建表,CREATE TABLE table_name like
create table stu4 like stu2;
-- 查看表类型和详情
DESC FORMATTED stu2;
删除内部表:
DROP TABLE table_name
:删除表
删除内部表,表信息以及表数据全部都被删除
外部表,创建表被EXTERNAL
关键字修饰,从概念是被认为并非Hive拥有的表
,只是临时关联数据去使用。创建外部表也很简单,基于外部表的特性,可以总结出: 外部表 和 数据 是相互独立的。
LOCATION
中LOCATION
指向数据先创建外部表,然后移动数据到location
目录:
-- 1. 首先创建文件 test_external.txt,并添加如下内容
1 hadoop
2 spark
3 hive
-- 2. 创建外部表:
create external table test_ext1(id int, name string) row format delimited fields terminated by ‘\t’ location ‘/tmp/test_ext1’;
-- 3. 可以看到,目录/tmp/test_ext1被创建
select * from test_ext1,空结果,无数据
-- 4. 上传数据:
hadoop fs -put test_external.txt /tmp/test_ext1/
-- 5. 查看数据
select * from test_ext1
先存在数据,后创建外部表:
-- 1. hdfs上创建目录
hadoop fs -mkdir /tmp/test_ext2
-- 2. 上传文件到hdfs指定目录下
hadoop fs -put test_external.txt /tmp/test_ext2/
-- 3. 创建外部表,指定数据地址
create external table test_ext2(id int, name string) row format delimited fields terminated by ‘\t’ location ‘/tmp/test_ext2’;
-- 4. 查询数据
select * from test_ext2;
删除外部表:
drop table test_ext1;
drop table test_ext2;
外部表删除后,表的元数据信息不存在了,但是hdfs上的数据文件依旧存在
-- 内部表转外部表
alter table stu set tblproperties('EXTERNAL'='TRUE');
-- 外部表转内部表
alter table stu set tblproperties('EXTERNAL'='FALSE');
可以通过desc formatted stu;
语句查看表类型
LOAD关键字
加载数据使用load
语法将外部数据加载到hive
内
LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename;
LOAD
:加载数据关键字[LOCAL]
:数据是否在本地,如果使用了local关键字,数据不在HDFS,需要使用file://协议指定路径
;不使用local关键字,数据在HDFS,可以使用hdfs://协议指定路径
[OVERWRITE]
:是否覆盖已经存在的数据,使用overwrite
进行覆盖,不使用``overwrite
则不覆盖-- 加载本地数据到hive表中
load data local inpath '/home/hadoop/search_log.txt' into table myhive.test_load;
-- 加载hdfs中的数据到表中
load data inpath '/tmp/search_log.txt' overwrite into table myhive.test_load;
注意:基于HDFS进行load加载数据,源数据文件会消失(本质是被移动到表所在的目录中)
INSERT SELECT
加载数据通过SQL语句查询的方式,将查询语句的结果插入到其他表中,被SELECT
查询的表可以是内部表或者外部表
INSERT [OVERWRITE | INTO] TABLE tablename1 [PARTITION (partcol1=val1, partcol2=val2 ...) [IF NOT EXISTS]] select_statement1 FROM from_statement;
INSERT INTO TABLE tbl1 SELECT * FROM tbl2;
-- 覆盖加载
INSERT OVERWRITE TABLE tbl1 SELECT * FROM tbl2;
load data local
LOAD
方式加载;如果保留原始文件,推荐使用外部表先关联数据,然后通过INSERT SELECT
外部表的形式加载数据INSERT SELECT
insert overwrite
将hive表中的数据导出到其他任意目录,例如linux本地磁盘,例如hdfs,例如mysql等
insert overwrite [local] directory ‘path’ select_statement1 FROM from_statement;
-- 将查询的结果导出到本地 - 使用默认列分隔符
insert overwrite local directory '/home/hadoop/export1' select * from test_load ;
-- 将查询的结果导出到本地 - 指定列分隔符
insert overwrite local directory '/home/hadoop/export2' row format delimited fields terminated by '\t' select * from test_load;
-- 将查询的结果导出到HDFS上(不带local关键字)
insert overwrite directory '/tmp/export' row format delimited fields terminated by '\t' select * from test_load;
hive shell
-- 执行SQL语句的方式导出
bin/hive -e "select * from myhive.test_load;" > /home/hadoop/export3/export4.txt
-- 执行SQL脚本的方式导出
bin/hive -f export.sql > /home/hadoop/export4/export4.txt
建表语句
create table myhive.test_array(name string, work_locations array<string>)
row format delimited fields terminated by '\t'
COLLECTION ITEMS TERMINATED BY ',';
row format delimited fields terminated by '\t'
:表示列分隔符是\t
COLLECTION ITEMS TERMINATED BY ','
:表示集合(array)元素的分隔符是逗号查询相关
-- 1. 查询所有数据
select * from myhive.test_array;
-- 2. 查询loction数组中第一个元素
select name, work_locations[0] location from myhive.test_array;
-- 3. 查询location数组中元素的个数
select name, size(work_locations) location from myhive.test_array;
-- 4. 查询location数组中包含tianjin的信息
select * from myhive.test_array where array_contains(work_locations,'tianjin');
map类型
其实就是简单的指代:Key-Value
型数据格式。 有如下数据文件,其中members字段
是key-value
型数据
字段与字段分隔符: “,”
;需要map字段
之间的分隔符:"#"
;map
内部k-v
分隔符:":"
id,name,members,age
1,zhangsan,father:xiaoming#mother:xiaohuang#brother:xiaoxu,28
2,lisi,father:mayun#mother:huangyi#brother:guanyu,22
3,wangwu,father:wangjianlin#mother:ruhua#sister:jingtian,29
4,mayun,father:mayongzhen#mother:angelababy,26
建表语句
-- MAP KEYS TERMINATED BY ':' 表示key-value之间用:分隔;COLLECTION ITEMS TERMINATED BY '#'表示map类型数据之间的数据用#分割
create table myhive.test_map(
id int, name string, members map<string,string>, age int
)
row format delimited
fields terminated by ','
COLLECTION ITEMS TERMINATED BY '#'
MAP KEYS TERMINATED BY ':';
常用查询
# 1. 查询全部
select * from myhive.test_map;
# 2. 查询father、mother这两个map的key
select id, name, members['father'] father, members['mother'] mother, age from myhive.test_map;
# 3. 查询全部map的key,使用map_keys函数,结果是array类型
select id, name, map_keys(members) as relation from myhive.test_map;
# 4. 查询全部map的value,使用map_values函数,结果是array类型
select id, name, map_values(members) as relation from myhive.test_map;
# 5. 查询map类型的KV对数量
select id,name,size(members) num from myhive.test_map;
# 6. 查询map的key中有brother的数据
select * from myhive.test_map where array_contains(map_keys(members), 'brother');
struct类型
是一个复合类型,可以在一个列中存入多个子列,每个子列允许设置类型和名称
-- 字段之间用#分割,struct之间冒号分割
1#周杰轮:11
2#林均杰:16
3#刘德滑:21
4#张学油:26
5#蔡依临:23
建表语句
create table myhive.test_struct(
id string, info struct<name:string, age:int>
)
row format delimited
fields terminated by '#'
COLLECTION ITEMS TERMINATED BY ':';
常用查询
-- 直接使用列名.子列名 即可从struct中取出子列查询
select ip, info.name from hive_struct;
在Hive中,我们可以把大的数据,按照每天,或者每小时进行切分成一个个的小文件,这样操作小文件速度就会快很多而且更加容易
如下图student表,按照月份进行分区(单分区表),每个分区就是一个文件夹
同时Hive也支持多个字段分区,多分区带有层级关系,如下图:
语法如下:
create table tablename(...) partitioned by (分区列 列类型, ......)
row format delimited fields terminated by '';
相关示例如下:
-- 1. 创建普通分区表
create table score(id string, score int) partitioned by (month string) row format delimited fields terminated by '';
-- 1.1 加载数据到普通分区表中
load data local inpath 'score.txt' into table score partition(month='202304')
-- 2. 创建一个表带有多个分区
create table score(id string, score int) partitioned by (year string, month string, day string) row format delimited fields terminated by '';
-- 2.1 加载数据到一个多分区的表中
load data local inpath 'score.txt' into table score partition(year='2023', month='04', day='01')
-- 3. 查看分区
show partitions score;
-- 4. 添加一个分区
alter table score add partition(month='202305');
-- 5. 同时添加多个分区,添加分区后可以在hdfs文件系统中看到表下面多了文件夹
alter table score add partition(month='202304') partition(month='202305')
-- 6. 删除分区
alter table score drop partition(month='202306')
分桶和分区一样,也是一种通过改变表的存储模式,从而完成对表优化的一种调优方式。但和分区不同,分区是将表拆分到不同的子文件夹中
进行存储,而分桶是将表拆分到固定数量的不同文件
中进行存储
-- 1. 开启分桶的自动优化(自动匹配reduce task数量和桶数量一致)
set hive.enforce.bucketing=true;
-- 2. 通过 clustered by指定分桶字段,into num buckets指定分桶数量
create table course (c_id string,c_name string,t_id string) clustered by(c_id) into 3 buckets row format delimited fields terminated by '\t';
分桶表的数据加载通过load data
无法执行,只能通过insert select
insert select
从临时表向分桶表中插入数据-- 1. 创建临时表
create table course(id string, name string) row format delimited fields terminated by '\t';
-- 2. 向普通表中加载数据
load data local inpath 'course.txt' into table course;
-- 3. 通过 insert overwrite select给分桶表加载数据
insert overwrite table course select * from course cluster by(id);
为什么分桶表加载数据不可以使用load data
,只能使用insert select
插入数据?
一旦有了分桶设置,比如分桶数量为3,那么,表内文件或分区内数据文件的数量就限定为3,当数据插入的时候,需要一分为3,进入三个桶文件内。那么如何将数据分成三份,划分的规则是什么?数据的三份划分基于分桶列的值进行hash取模
来决定。由于load data不会触发MapReduce,也就是没有计算过程(无法执行Hash算法)
,只是简单的移动数据而已,所以无法用于分桶表数据插入。因此必须使用insert select
的语法,因为会触发MapReduce,进行hash取模计算
。
分桶表的性能提升:
同样的数据被Hash加密后的结果是一致的,如hadoop hash取模结果是1,无论计算多少次,字符串hadoop的取模结果都是1。因此同样key(分桶列的值)的数据,会在同一个桶中。
表的重命名
语法:alter table old_table_name rename to new_table_name;
alter table score rename to score5;
修改表属性值
语法:ALTER TABLE table_name SET TBLPROPERTIES table_properties;
-- 修改内外部表属性
ALTER TABLE table_name SET TBLPROPERTIES("EXTERNAL"="TRUE");
-- 修改表注释
如:ALTER TABLE table_name SET TBLPROPERTIES ('comment' = new_comment);
更多属性修改:https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-listTableProperties
添加分区
ALTER TABLE tablename ADD PARTITION (month='201101');
新分区是空的没数据,需要手动添加或上传数据文件
修改分区值
ALTER TABLE tablename PARTITION (month='202304') RENAME TO PARTITION (month='202305');
删除分区
ALTER TABLE tablename DROP PARTITION (month='202304');
添加列
ALTER TABLE table_name ADD COLUMNS (v1 int, v2 string);
修改列名
ALTER TABLE test_change CHANGE v1 v1new INT;
删除表
DROP TABLE tablename;
清空表
-- 只能清空内部表
TRUNCATE TABLE tablename;