Hive是一个基于 Hadoop 的数据仓库工具,可以将结构化的数据文件映射成一张数据表,并可以使用类似SQL的方式来对数据文件进行读写以及管理。这套Hive SQL 简称HQL。Hive的执行引擎可以是MR、Spark、Tez。
本质
Hive的本质是将HQL转换成MapReduce任务,完成整个数据的分析查询,减少编写MapReduce的复杂度 。
优点
1.学习成本低:提供了类SQL查询语言HQL,使得熟悉SQL语言的开发人员无需关心细节,可以快速上手.
2.海量数据分析:底层是基于海量计算到MapReduce实现.
3.可扩展性:为超大数据集设计了计算/扩展能力(MR作为计算引擎,HDFS作为存储系统),Hive可以自由的扩展集群的规模,一般情况下不需要重启服务。
4.延展性:Hive支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。
5.良好的容错性:某个数据节点出现问题HQL仍可完成执行。
6.统计管理:提供了统一的元数据管理
缺点
1.Hive的HQL表达能力有限
2.迭代式算法无法表达.
3.Hive的效率比较低.
4.Hive自动生成的MapReduce作业,通常情况下不够智能化.
5.Hive调优比较困难,粒度较粗.
UI:主要是Hive的各种客户端。这是用户使用Hive的窗口,包括我们之前使用的HiveCli、Beeline等CLI,以及一些Web GUI接口。用户通过UI来提交自己的操作请求。
Driver:接收用户查询,并且实现了会话处理,基于JDBC/ODBC实现了执行、拉取数据等API。
Compiler:解析查询语句,做语义分析,最终借助在Metastore中查询到的表和分区的元数据生成执行计划(execution plan),这个和传统的RDBMS比较像。当然其实Hive也有优化器(Optimizer),图中没有画出来。
Metastore:存储表和分区的元数据信息,包括字段、字段类型、读写数据需要的序列化和反序列化信息。
Execution Engine:执行引擎,用来执行Compiler生成的执行计划,是Hive和Hadoop之间的桥梁。现在Hive支持的计算引擎包括MR(逐渐废弃)、Tez、Spark。
下面我们看看一下一次查询的完整流程(下面的step n对应图中的数组序号):
在Hive中,表类型主要分为两种:
内部表: 也叫管理表,表目录会创建在hdfs的/user/hive/warehouse/下的相应的库对应的目录中。
外部表: 外部表会根据创建表时LOCATION指定的路径来创建目录,如果没有指定LOCATION,则位置跟内部表相同,一般使用的是第三方提供的或者公用的数据。
内部表和外部表在创建时的差别
内部表
CRAATE TABLE T_INNER(ID INT);
外部表
CREATE EXTERNAL TABLE T_OUTER(ID INT) LOCATION 'HDFS:///AA/BB/CC';
Hive表创建时要做的两件事:
drop时有不同的特性:
使用场景
内部表:平时用来测试或者少量数据,并且自己可以随时修改删除数据。
外部表使用后数据不想被删除的情况使用外部表(推荐)所以,整个数据仓库的最底层的表使用外部表。
1. 注释语法:
-- 单行注释
// 单行注释
/*
* 多行注释
*/
2. 大小写规则:
Hive的数据库名、表名都不区分大小写
建议关键字大写
3. 命名规则:
4. 快速创建库和表:
-- hive有一个默认的数据库default,如果不明确的说明要使用哪个库,则使用默认数据库。
hive> create database user;
hive> create database if not exists user;
hive> create database if not exists db comment 'this is a database of practice';
-- 创建库的本质:在hive的warehouse目录下创建一个目录(库名.db命名的目录)
-- 切换库:
hive> use uer;
--创建表
hive> create table t_user(id int,name string);
-- 使用库+表的形式创建表:
hive> create table db.t_user(id int,name string);
--创建表时加上加载数据的分隔符
create table t_user ( id int, name string )
row format delimited fields terminated by ',';
5.查看表
# 查看当前数据库的表
show tables;
# 查看另外一个数据库中的表
show tables in zoo;
# 查看表信息
desc tableName;
# 查看详细信息
desc formatted tableName;
#查看创建表信息
show create table tableName;
6.修改表
修改表名
alter table t7 rename to a1;
修改列名
alter table a1 change column name name1 string;
修改列的位置
alter table log1 change column ip ip string after status;
修改字段类型+修改注释
alter table a1 change column name1 name string comment '修改字段名';
增加字段
alter table a1 add columns (sex int);
替换字段
alter table a1 replace columns
( id int, name string, size int, pic string );
内部表和外部表转换
内部表转外部表,true 一定要大写;
alter table a1 set tblproperties('EXTERNAL'='TRUE');
false大小写都没有关系
alter table a1 set tblproperties('EXTERNAL'='false');
7.加载数据到Hive
-- 从hdfs中加载数据
hive> load data inpath 'hivedata/user.csv' into table user;
-- 从本地加载数据
hive> load data local inpath 'hivedata/user.csv' into table user;
加载数据的本质:
注意:
Hive使用的是严格的读时模式:加载数据时不检查数据的完整性,读时发现数据不对则使用NULL来代替。
Mysql使用的是写时模式:在写入数据时就进行检查。
create table usernew(
id int,
name string
)
comment 'this is a table'
row format delimited fields terminated by ','
lines terminated by '\n' stored as textfile;
不带数据,只克隆表的结构
-- 从usernew 克隆新的表结构到userold
create table if not exists userold like usernew;
克隆表并带数据
create table t7
as
select * from t6;
8.Hive Shell技巧
查看所有hive参数
hive> set
只执行一次Hive命令
[root@hadoop01 hive]# hive -e "select * from cat"
单独执行一个sql文件
[root@hadoop01 hive]# hive -f /path/cat.sql
执行Linux命令
加上前缀! 最后以分号;结尾,可以执行linux的命令
hive> ! pwd ;
执行HDFS命令
hive> dfs -ls /tmp
1.分区的原因
随着系统运行的时间越来越长,表的数据量越来越大,而hive查询通常是使用全表扫描,这样 会导致大量不必要的数据扫描,从而大大降低了查询的效率。
为了提高查询的效率,从而引进分区技术,使用分区技术,能避免hive做全表扫描,从而提交查询效率。可以将用户的整个表在存储上分成多个子目录(子目录以分区变量的值来命名)。
可以让用户在做数据统计的时候缩小数据扫描的范围,因为可以在select是指定要统计 哪个分区,譬如某一天的数据,某个地区的数据等.
分区本质
在表的目录或者是分区的目录下在创建目录,
分区的目录名为指定字段=值
2.创建分区表
通过下面的 partitioned by 指定分区名,另外分区名(dt)是一个伪字段,是在part1之外的字段
create table if not exists part1(
id int,
name string
)
-- 根据需求选择,数据非常大才需要三级分区
-- 一级分区
partitioned by (dt string)
-- 二级分区
partitioned by (year string,month string)
-- 三级分区
partitioned by (year string,month string,day string)
row format delimited fields terminated by ',';
3.分区表基本操作
-- 一级分区
load data local inpath "/opt/data/user.txt" into table part1
partition(dt="2019-08-08");
-- 二级分区
load data local inpath '/opt/soft/data/user.txt' into table part2
partition(year='2020',month='02');
-- 三级分区
load data local inpath '/opt/soft/data/user.txt' into table part3
partition(year='2020',month='02',day='20');
alter table part5 add partition(dt='2020-03-21');
alter table part5 add partition(dt='2020-11-11')
location '/user/hive/warehouse/part1/dt=2019-08-08';
alter table part5 partition(dt='2020-03-21')
set location 'hdfs://hadoop01:8020/user/hive/warehouse//part1/dt=2019-09-11'
alter table part5 drop partition(dt='2020-03-24'),partition(dt='2020-03- 26');
4.分区表类型
加载数据到指定分区的值,新增分区或者加载分区时指定分区名
数据未知,根据分区的值来确定需要创建的分区。
动态分区的属性配置
是否能动态分区
hive.exec.dynamic.partition=true
设置为非严格模式
hive.exec.dynamic.partition.mode=nonstrict
最大分区数
hive.exec.max.dynamic.partitions=1000
最大分区节点数
hive.exec.max.dynamic.partitions.pernode=100
创建动态分区表
create table dy_part1(
id int,
name string
)
partitioned by (dt string)
row format delimited fields terminated by ',';
加载数据
先创建临时表导入数据后:
insert into dy_part1 partition(dt)
select id,name,dt from temp_part;
静态和动态都有。
创建混合分区表
create table dy_part2(
id int,
name string
)
partitioned by (year string,month string,day string)
row format delimited fields terminated by ',';
加载数据
先创建临时表导入数据后:
insert into dy_part2 partition (year='2020',month,day)
select id,name,month,day from temp_part2;
1.hive的分区使用的是表外字段,分区字段是一个伪列,但是分区字段是可以做查询
过滤。
2.分区字段不建议使用中文
3.一般不建议使用动态分区,因为动态分区会使用mapreduce来进行查询数据,如果分区数据过多,导致 namenode 和 resourcemanager 的性能瓶颈。所以建议在使用动态分区前尽可能预知分区数量。
4.分区属性的修改都可以使用修改元数据和hdfs数据内容。
1.分桶的意义
当单个的分区或者表的数据量过大,分区不能更细粒度的划分数据,就需要使用分桶技术将数 据划分成更细的粒度。
2. 关键字及其原理
bucket
分桶的原理:跟MR中的HashPartitioner原理一样,都是key的hash值取模reduce的数量
MR中:按照key的hash值除以reduceTask取余
Hive中:按照分桶字段的hash值取模除以分桶的个数
3.分桶表的操作
create table t_stu(
Sno int,
Sname string,
Sex string,
Sage int,
Sdept string
)
row format delimited fields terminated by ','
stored as textfile;
load方式加载数据不能体现分桶
load data local inpath '/root/hivedata/students.txt' into table t_stu;
临时表方式
加载数据到临时表
load data local inpath '/hivedata/buc1.txt' into table temp_buc1
使用分桶查询将数据导入到分桶表
insert overwrite table buc13
select id,name,age from temp_buc1
cluster by (id);
语法:
tablesample(bucket x out of y on sno)
注意:tablesample一定是紧跟在表名之后 x:代表从第几桶开始查询 y:查询的总桶数,y可以是总桶数的倍数或者因子,x不能大于y
默认有4桶
查询第一桶
select * from buc3 tablesample(bucket 1 out of 4 on sno);
查询第一桶和第三桶
select * from buc3 tablesample(bucket 1 out of 2 on sno);
查询第一桶的前半部分
select * from buc3 tablesample(bucket 1 out of 8 on sno);
y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。例如,table总共分了4份,当y=2时,抽取(4/2=)2个bucket的数据,当y=8时,抽取(4/8=)1/2个bucket的数据。
x表示从哪个bucket开始抽取,如果需要取多个分区,以后的分区号为当前分区号加上y。例如,table总bucket数为4,tablesample(bucket 1 out of 2),表示总共抽取(4/2=)2个bucket的数据,抽取第1(x)个和第3(x+y)个bucket的数据。
注意:x的值必须小于等于y的值,否则
FAILED: SemanticException [Error 10061]: Numerator should not be bigger than denominator in sample clause for table stu_buck
查询sno为奇数的数据
select * from buc3 tablesample(bucket 2 out of 2 on sno);
查询sno为偶数且age大于30的人
select * from buc3 tablesample(bucket 1 out of 2 on sno) where age>30;
查出三行
select * from buc3 limit 3;
查出三行
select * from buc3 tablesample(3 rows);
查出13%的内容,(如果百分比不够现实 一行,至少会显示一行,如果百分比为0,显示第一桶)
select * from buc3 tablesample(13 percent);
查出68B包含的数据,如果是 0B,默认显示第一桶 要求随机抽取3行数据:
select * from buc3 tablesample(68B);
随机显示3条数据
select * from t_stu order by rand() limit 3;