目录
1、Hive的DDL(data define language)
2、Hive的DML(data managed language)操作
1、Hive的DDL(data define language)
1.1、库的操作
1)创建数据库
create database name;
2)切换库
use name;
3)查看库列表
show databases;
show databases like 'test*';
4)查看数据库的描述信息
desc database name; 或 desc database extended db_name; #查看数据库的详细信息
5)查看正在使用的库
select current_database();
6)删除库
drop database name; 只能删除空的
drop database name restrict; 严格模式下的删除库 会进行库的检查 如果库不是空的不允许删除
drop database name cascade; 删除非空数据库 级联删除
防报异常操作:
创建库和删除库的时候 为了防止异常
if not exists 建库
create database if not exists test;
不存在则创建 存在则直接返回
if exists 删除库
drop database if exists test;
这两个操作同样适用于表和分区的操作
1.2、表的操作
1.2.1、创建表
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 AS file_format]
[location hdfs_path]
语法说明:
1)external 关键字
加上这个关键字 建的表是外部表
不加这个关键字 建的表就是内部表
内部表和外部表的区别:
1)概念本质上
内部表数据自己的管理的在进行表删除时数据和元数据一并删除。
外部表只是对HDFS的一个目录的数据进行关联,外部表在进行删除时只删除元数据, 原始数据是不会被删除的。
2)应用场景上
外部表一般用于存储原始数据、公共数据,内部表一般用于存储某一个模块的中间结果数据。
3)存储目录上
外部表:一般在进行建表时候需要手动指定表的数据目录为共享资源目录,用lication关键字指定。
内部表:无严格的要求,一般使用的默认目录。
外部表测试:
外部表的共享资源路径:
/source/log
部门1:建表
create external table log1(course string,name string,score int) row format delimited fields terminated by ','
location '/source/log';
部门2:建表
create external table log2(course string,name string,score int) row format delimited fields terminated by ','
location '/source/log';
外部表的数据如何彻底删除:
1)drop table tablename;
2)在去HDFS的对应的数据存储目录 hadoop fs -rm -r path
2)if not exists 防止报错的
3)comment 指定列或表的描述信息
4)[partitioned by (col_name data_type [COMMENT col_comment] , ...)]
partitioned by 指定分区字段
partitioned by(分区字段名 分区字段类型 COMMENT 字段描述信息)
注意:分区字段一定不能存在于建表字段中。
5)[clustered by (col_name, col_name, ...) [sorted by (col_name [ASC|DESC], ...)] into num_buckets buckets]
这部分语句是用来指定分桶的。
clustered by (col_name, col_name, ...) 指定分桶字段
注意:分桶字段一定是建表字段中的一个或几个
sorted by 指定的是每一个桶表中的排序规则
into num_buckets buckets 指定桶的个数
6)[row format row_format] 指定分割符的
fields terminated by 列分割符
lines terminated by 行分割符
map keys terminated by
7)[stored as AS file_format] 指定原始数据的存储格式
textfile 文本格式 默认的方式
cfile 行列格式
在行的方向切分数据的存储的块 保证一行数据在一个数据块中
每列个块中存储的时候 进行划分存储的
SequenceFile 二进制存储格式
8)location 指定原始数据的存储位置的
一定是hdfs上的路径
这里没有指定 读取配置文件中的 hive-site.xml
如果指定则会覆盖配置文件中的位置
注:hive的原始数据存储的配置说明
1)hive-default.xml 2)hive-site.xml 3)建表语句 LOCATION
加载顺序:1)---2)---3)
生效:最后加载的最终生效
创建表的案例:
1)创建一个内部表
1307 7048 吴芷馨 95 96 98
create table if not exists student (grade int,stu_id int,name string,yuwen string,shuxue string,yingyu string) COMMENT 'studnet score'
row format delimited fields terminated by '\t'
lines terminated by '\n'
stored as textfile
location '/user/data/student';
2)创建一个外部表
create external table if not exists student_external (grade int,stu_id int,name string,yuwen string,shuxue string,yingyu string) COMMENT 'studnet score'
row format delimited fields terminated by '\t'
lines terminated by '\n'
stored as textfile
location '/user/data/student_external';
3)创建一个分区表
选择一个分区字段:根据过滤条件
分区字段 grade
create external table if not exists student_ptn (stu_id int,name string,yuwen string,shuxue string,yingyu string)
COMMENT 'student score in partitions grade'
partitioned by (grade int)
row format delimited fields terminated by '\t';
分区表的字段一定不能是建表字段 。
4)创建一个分桶表
分桶字段:name 排序:yuwen shuxue yingyu desc
桶个数3
分桶表的字段一定在建表语句中
create external table if not exists student_buk (grade int,stu_id int,name string,yuwen string,shuxue string,yingyu string)
clustered by (name) sorted by (yuwen desc,shuxue desc,yingyu desc) into 3 buckets
row format delimited fields terminated by '\t' ;
5)进行表复制
关键字 like
create table if not exists stu_like like student;
只会复制表结构,表的属性(表的存储位置 表的类型)不会被复制的。
6)ctas语句建表
create table tablename as select .... from ...
将sql语句的查询结果存放在一个表中。
1.2.2、查看表的描述信息
desc tablename; 只能查看表的字段信息
desc extended tablename; 查看表的详细描述信息 所有的信息放在一行的
desc formatted tablename; 格式化显示表的详细信息 ****
1.2.3、查看表的列表
show tables; 查看当前数据库的表列表信息
show tables in dbname; 查看指定数据库的表列表信息
show tables like 'student*';
show partitions tablename; 查询指定表下的所有分区
1.2.4、表的修改
1)表的重命名
alter table tablename rename to newname;
alter table stu_like01 rename to student_copy;
修改元数据信息也可以
2)修改列
1)增加列
alter table tablename add columns (name type);
alter table student_copy add columns (content string);
2)修改列
alter table tablename change oldname newname type;
修改列名
alter table student_copy change content text string;
修改列类型
alter table student_copy change text text int;
alter table student_copy change grade grade string;
hive2.0版本中对类型转换限制了
小类型----》大类型 允许的
大类型----》小类型 报错
3)替换列 了解
alter table tablename replace columns(name type);
alter table stu_test replace columns(id int);
3)修改分区信息
1)添加分区 根据分区字段进行添加
手动添加分区
alter table tablename add partition(name=value);
alter table student_ptn add partition(grade=1303);
1304 1305 1306 1307
alter table student_ptn add partition(grade=1304);
一次添加多个分区
alter table student_ptn add partition(grade=1305) partition(grade=1306) partition(grade=1307);
2)修改分区的存储位置
分区的默认存储位置:表的目录下创建的分区目录
/user/hive/hivedata/bd1808.db/student_ptn/grade=1303
我们可以手动指定某一个分区的存储位置:如下
添加分区的时候指定
alter table student_ptn add partition(grade=1308) location '/user/student/1308';
对于已经已添加的分区修改存储位置 了解
添加数据的时候才生效 不会立即生效的
alter table tablename partition(name=value) set location '';
alter table student_ptn partition(grade=1303) set location '/user/student/1303';
1.2.5、表/分区 数据的清空
truncate table tablename; 清空表
truncate table tablename partition(name=value); 清空某一个分区的数据
1.2.6、删除表
drop table if exists tablename;
1.2.7、查看详细建表语句
show create table table_name;
CREATE EXTERNAL TABLE `student_external`( `grade` int, `stu_id` int, `name` string, `yuwen` string, `shuxue` string, `yingyu` string) COMMENT 'studnet score' ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe' WITH SERDEPROPERTIES ( 'field.delim'='\t', 'line.delim'='\n', 'serialization.format'='\t') STORED AS INPUTFORMAT 'org.apache.hadoop.mapred.TextInputFormat' OUTPUTFORMAT 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat' LOCATION 'hdfs://hadoop01:9000/user/data/student_external' TBLPROPERTIES ( 'transient_lastDdlTime'='1542234385') |
2、Hive的DML(data managed language)操作
2.1、表的数据插入
2.1.1、load方式
语法:load data [local] inpath path into table tablename;
说明:
local 加上local关键字代表的是数据从本地导入
不加local关键字 代表的是数据从HDFS导入的
案例:
1)数据从本地导入
load data local inpath '/home/hadoop/tmpdata/score.txt' into table student_external;
本质是将数据从本地上传到hdfs的表存储目录下。
实验:
直接将本地的数据上传到Hive表的HDFS目录下
hadoop fs -put score.txt /user/data/student_external/score1.txt;
数据依然可以通过Hive查询到。
Hive中的表就是hdfs一个目录的数据的管理者,只要在这个目录下添加数据,数据不管符不符合规则都会被Hive加载到。
2)数据从HDFS加载
load data inpath '/sco_in/score.txt' into table student_external;
问题:
1)数据移动还是复制
这是数据移动的过程,不是复制的过程,数据是从HDFS的路径移动到Hive表空间的路径下。
2)同名的数据进行加载时文件名会不会冲突
没有冲突,在文件上传到表的管理空间的时候会对重名的文件重命名,比如 score_copy_1.txt
注意:上面的两种方式的最终结果都是将数据放在了Hive的表空间中。
2.1.2、insert的方式
常规数据插入方法:
1)单条数据插入 同mysql的单条数据插入,一次只能插入一条数据
insert into table tablename values();
insert into table student values(1303,2345,"xh",23,45,10);
这种插入方式会转换为MR任务执行效率低。
底层原理:将数据先插入到一个临时表values__tmp__table__2,再将此临时表中的数据读取并写出到hive表的管理空间中。
2)单重数据插入 一次性插入多条数据,将sql查询语句的查询结果进行插入
insert into table tablename select ....
insert into table student select * from student_external where yuwen>80;
需求:将student_external表中的 yuwen>80 的记录插入表student,shuxue>90的记录插入表student01
insert into table student select * from student_external where yuwen>80;
insert into table student01 select * from student_external where shuxue>90;
执行两个插入语句需对student_external表扫描两次,效率不高,所以,就引入下面的多重数据插入。
3)多重数据插入 对表扫描一次将数据插入到多个表中或者是同一个表的多个分区中
语法:
from tablename
insert into table table1 select ... where ...
insert into table table2 select ,,, where ..
from student_external
insert into table stu01 select * where yuwen>80
insert into table stu02 select * where shuxue>90;
两种特殊表的数据插入问题:即分区表 和 分桶表
1、分区表的数据插入 数据插入的时候必须指定分区
静态分区数据插入
静态:表的分区的值是手动静态指定的,在数据插入的时候需要手动指定分区的值
1)load的方式
load data [local] inpath '' into table tablename partition (name=value);
说明:partition 用于指定分区名的,后面的括号中给的就是分区名key=value
例子:
load data local inpath '/home/hadoop/tmpdata/score.txt' into table student_ptn partition (grade=1303);
注意:这种方式进行数据加载时不会进行数据检查,在用这种方式加载数据时一定要十分确定数据是这个分区的。
生产中:分区字段选择时间,即一天一个分区,比如 date=20181120,采集数据是按照时间收集的 。
以上方式加载数据时是按照建表语句中的字段顺序去解析文件中的列,最后一个字段会取进行加载数据时指定的分区值,
这种方式加载数据时分区字段的值不需要存储在原始数据中。
2)insert的方式 可以添加过滤条件,从一个非分区表抽取数据到分区表,将指定的数据放在指定的分区中。
单重数据插入方式
insert into table tablename partition(name=value) select .... from ..where...
insert into table student_ptn partition(grade=1304)
select stu_id,name,yuwen,shuxue,yingyu from student_external
where grade=1304;
这种方式在插入数据的时候一定要注意查询的字段和分区表中的字段匹配 一一对应
多重数据插入方式 一次扫描数据 插入到多个分区中
from student_external
insert into table student_ptn partition (grade=1305)
select stu_id,name,yuwen,shuxue,yingyu where grade=1305
insert into table student_ptn partition(grade=1306)
select stu_id,name,yuwen,shuxue,yingyu where grade=1306;
这种方式比较普遍 在数据插入的时候对数据进行检查
insert into 和insert overwrite区别:
insert into 追加写入。
insert overwrite 覆盖写入的,原来的数据被清空。
静态分区数据插入缺点:数据足够大,分区足够多的时候,分区的值不确定的时候,这个时候静态分区比较麻烦。
动态分区数据插入
分区的值随着数据的插入动态生成的,数据在查询时需要将分区字段也查询出来。
数据插入方式只能使用insert的方式不能使用load的方式。
insert into table tablename partition(分区字段(分区字段不需要给值)) select … from table
案例:
insert into table student_ptn partition(grade) select * from student_external;
student_ptn:默认分区字段都在最后的
stu_id int
name string
yuwen string
shuxue string
yingyu string
grade int
student_external:
grade int
stu_id int
name string
yuwen string
shuxue string
yingyu string
修正:
insert into table student_ptn partition(grade) select stu_id,name,yuwen,shuxue,yingyu,grade from student_external;
关闭严格模式:set hive.exec.dynamic.partition.mode=nonstrict;
注意:动态分区中必须将分区字段放在查询语句的最后,因为分区表中会自动将分区字段放在表的普通字段的后面。
动态分区和静态分区的区别:
1)静态分区的分区手动指定的——动态分区的分区根据数据自动生成的
2)静态分区可能存在某一个分区数据为空的情况——动态分区每一个分区中至少都有一条数据的不存在空分区的可能
3)动态分区比较消耗性能
动态分区中如果设置reducetask的个数,那么对每一个动态分区都是有效的。
set reducetasks=3; 每一个分区都会启动3个reducetask,在动态分区中一定要慎重使用reducetask的个数。
多级分区:
分区字段超过一个叫做多级分区,多级分区之间必然存在从属关系
partition(name,age),name称为高级分区或一级分区,age称为二级分区
分区时先根据高级分区再根据低级分区。
创建一个多级分区的表 分区字段:过滤条件
create table if not exists student_ptn01 (stu_id int,name string,shuxue string,yingyu string)
COMMENT 'student score in partitions grade'
partitioned by (grade int,yuwen string)
row format delimited fields terminated by '\t';
数据插入:
静态:
1)两个分区都是静态
alter table student_ptn01 add partition(grade=1303,yuwen='34');
/user/hive/hivedata/bd1808.db/student_ptn01/grade=1303/yuwen=34
2)只有一个是静态分区 另外一个是动态分区
这个静态分区只能是高级分区 insert的时候可以指定
alter table student_ptn01 add partition(grade=1304); 错
load
load data local inpath '/home/hadoop/tmpdata/score.txt' into table student_ptn01 partition(grade=1303,yuwen='34');
insert 可以
insert into table student_ptn01 partition(grade=1303,yuwen)
select stu_id,name,shuxue,yingyu,yuwen from student_external
where grade=1303;
动态:
insert into table student_ptn01 partition(grade,yuwen)
select stu_id,name,shuxue,yingyu,grade,yuwen from student_external;
2、分桶表的数据插入
1)load方式 不支持
load data local inpath '/home/hadoop/tmpdata/score.txt' into table student_buk;
每一个桶的数据:分桶字段.hash%桶的个数
load的方式在进行数据加载的时候不会进行数据字段的检查的,无法匹配分桶字段,无法识别任何字段的。
2)insert ...selelct
insert into table student_buk select * from student_external;
运行日志:Number of reducers (= 3) is more than 1
自动按照分桶个数启动相应个数的reducetask任务
分桶算法:
分桶字段string 默认的 分桶字段.hash%桶的个数
分桶字段数值类型的时候 分桶字段%分桶个数
2.2、数据导出
将表中的数据导出成文件
1)单模式导出 单重数据导出
insert overwrite [local] directory directory1 select_statement
说明:
1)overwrite 覆盖写出
2)local 加上 导出本地 不加 hdfs
3)directory 指定的是本地或hdfs的路径
insert overwrite local directory '/home/hadoop/tmpdata/test_hive' select * from student_buk where grade=1303;
2)多模式导出: 多重导出
from from_statement
insert overwirte [local] directory directory1 select_statement1
[insert overwirte [local] directory directory2 select_statement2] ...
2.3、数据查询
语法:join、where、group by、order by、having、limit
select ... from .. join ....where .. group by .. having ...order by
执行顺序:mysql
from ——>join ——>where ——>group by ——>select ——>having ——>order by
2.3.1、join
数据准备:
a表 | b表 | ||
id | name | id | age |
1 | zs | 1 | 45 |
2 | ls | 3 | 58 |
1、内连接 [inner] join
两个表中关联键相同的记录才会查询出来。
select * from a inner join b on a.id=b.id;
结果:1 zs 1 45
2、外连接——左外连接
以左表为主表,右表中有的就会关联上,右表中没有关联上的数据就用 null 补齐。
select * from a left outer join b on a.id=b.id;
结果:
1 zs 1 45
2 ls NULL NULL
3、外连接——右外连接
以右表为主表,左表有的则关联,没有则null补齐
select * from a right outer join b on a.id=b.id;
结果:
1 zs 1 45
NULL NULL 3 58
4、外连接——全外连接 full outer join
左表和右表中的并集,左表和右表中所有的数据都会关联上
select * from a full outer join b on a.id=b.id;
结果:
1 zs 1 45
2 ls NULL NULL
NULL NULL 3 58
5、半连接 left semi join左半连接
mysql中有一个语法 in/exists 用于判断字段是否在给定的值中
对于hql语句 去执行这个语句的时候需要转换为MR任务 in/exists hive在
转换为MR任务的时候性能极低 这时候我们通用的解决方案就是用join解决。
select * from a left semi join b on a.id=b.id;
左半连接:判断左表中的关联建是否在右表中存在 ,若存在,则返回左表的存在的数据的相关字段,若不存在,则不返回。
2.3.2、where
多个过滤条件 and or
2.3.3、group by 分组
1)group by的执行顺序是在select之前,所以,group by不可使用select中的别名
2)当查询语句中有group by时select的字段后面只能跟两种形式的数据
聚合函数 和 group by的字段
3)案例:每一个班级的参考人数
select grade as g,avg(yuwen) from student_buk group by grade;
2.3.4、hive中的排序的几个by
Hive中的几个排序的by分别是:order by、sort by 、distribute by、cluster by
1)order by 排序字段 asc|desc
全局排序,针对所有的reduecetask进行全局排序
select * from student_buk order by yuwen desc limit 20;
set mapreduce.job.reduces=3;
2)sort by 局部排序
针对每一个reducetask的结果进行排序的,不保证全局排序, 只有一个reducetask的时候 sort by = order by
select * from student_test sort by age desc;
进行数据分区的时候每次随机选择的一个字段进行分区的,随机选择的字段.hash%reducetask的个数
reducetask0
95003 王敏 女 22 MA
95020 赵钱 男 21 IS
95012 孙花 女 20 CS
95001 李勇 男 20 CS
95004 张立 男 19 IS
95019 邢小丽 女 19 IS
95014 王小丽 女 19 CS
95008 李娜 女 18 CS
95011 包小柏 男 18 MA
reducetask1
95013 冯伟 男 21 CS
95022 郑明 男 20 MA
95018 王一 女 19 IS
95007 易思玲 女 19 MA
95010 孔小涛 男 19 CS
95017 王风娟 女 18 IS
95009 梦圆圆 女 18 MA
95005 刘刚 男 18 MA
reducetask2
95006 孙庆 男 23 CS
95002 刘晨 女 19 IS
95015 王君 男 18 MA
95021 周二 男 17 MA
3)distribute by 分桶 查询的时候的分桶
分桶的个数=reducetask的个数,distribute by 后面指定的是分桶字段,对查询结果进行分桶
select * from student_test distribute by age;
每个桶的数据分配依据:
string 分桶字段.hash%reducetask的个数
数值 分桶字段%reducetask的个数
桶0 age%3===0
95015 王君 男 18 MA
95005 刘刚 男 18 MA
95011 包小柏 男 18 MA
95017 王风娟 女 18 IS
95013 冯伟 男 21 CS
95020 赵钱 男 21 IS
95008 李娜 女 18 CS
95009 梦圆圆 女 18 MA
桶1 age%3===1
95010 孔小涛 男 19 CS
95007 易思玲 女 19 MA
95004 张立 男 19 IS
95003 王敏 女 22 MA
95019 邢小丽 女 19 IS
95014 王小丽 女 19 CS
95018 王一 女 19 IS
95002 刘晨 女 19 IS
桶2 age%3===2
95012 孙花 女 20 CS
95022 郑明 男 20 MA
95001 李勇 男 20 CS
95021 周二 男 17 MA
95006 孙庆 男 23 CS
查询的时候,如果想指定某一个字段进行分桶,在每一个桶中进行排序,这个时候 distribute by 分桶字段+sort by 排序
select * from student_test distribute by age sort by age desc;
distribute by和sort by的字段可以不一样
95013 冯伟 男 21 CS
95020 赵钱 男 21 IS
95005 刘刚 男 18 MA
95015 王君 男 18 MA
95011 包小柏 男 18 MA
95017 王风娟 女 18 IS
95008 李娜 女 18 CS
95009 梦圆圆 女 18 MA
95003 王敏 女 22 MA
95010 孔小涛 男 19 CS
95007 易思玲 女 19 MA
95004 张立 男 19 IS
95019 邢小丽 女 19 IS
95014 王小丽 女 19 CS
95018 王一 女 19 IS
95002 刘晨 女 19 IS
95006 孙庆 男 23 CS
95012 孙花 女 20 CS
95001 李勇 男 20 CS
95022 郑明 男 20 MA
95021 周二 男 17 MA
4)cluster by
distribute by和 sort by的字段相同的时候=cluster by
现根据指定字段进行分桶 再根据指定的这个字段进行排序
分桶字段=排序字段
select * from student_test cluster by age;
注意: distribute by 和 sort by的字段不一致的时候不能使用,cluster by的
2.3.5、hive的查询语句什么时候会转换为MR任务
hive.fetch.task.conversion
Default Value: minimal in Hive 0.10.0 through 0.13.1,
more in Hive 0.14.0 and later
Added In: Hive 0.10.0 with HIVE-2925; default changed in Hive 0.14.0 with HIVE-7397
Some select queries can be converted to a single FETCH task, minimizing latency. Currently the query should be single sourced not having any subquery and should not have any aggregations or distincts (which incur RS – ReduceSinkOperator, requiring a MapReduce task), lateral views and joins.
Supported values are none, minimal and more.
0、none: 这个属性不可用 所有的hql都需要转换为MR
1、minimal:
SELECT *
FILTER on partition columns (WHERE and HAVING clauses) 过滤条件是分区字段
LIMIT
上面三种情况不会转换为MR的 其他的都会
2、more:
SELECT select任意字段
FILTER 过滤条件是任意字段
LIMIT
运行过程中:
一个reducetask的吞吐量
In order to change the average load for a reducer (in bytes):
set hive.exec.reducers.bytes.per.reducer=<number> 256M
设置全局的启动的所有的reduvetask的个数
In order to limit the maximum number of reducers:
set hive.exec.reducers.max=<number>
设置reducetask的个数
In order to set a constant number of reducers:
set mapreduce.job.reduces=<number> -1
根据实际情况自动分配:
当表是分桶表的时候自动将这个值赋值为桶表的个数
当表不是桶表的时候 没有reduce--0 有reduce---1