大数据工具——Hive(基础)

一、HIVE的定义

Hive是一个基于 Hadoop 的数据仓库工具,可以将结构化的数据文件映射成一张数据表,并可以使用类似SQL的方式来对数据文件进行读写以及管理。这套Hive SQL 简称HQL。Hive的执行引擎可以是MR、Spark、Tez。

本质
Hive的本质是将HQL转换成MapReduce任务,完成整个数据的分析查询,减少编写MapReduce的复杂度 。

二、Hive的优缺点

优点
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调优比较困难,粒度较粗.

三、Hive的架构

大数据工具——Hive(基础)_第1张图片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对应图中的数组序号):

  1. 用户通过UI提交自己的查询请求到Driver(step 1);
  2. Driver创建一个会话来处理用户的这次请求,将请求发到Compiler以生成执行计划(step 2);
  3. Compiler从Metastore获取一些必要的元数据信息(step 3、4),做类型检查以及一些优化操作,然后最终生成执行计划发送给Driver(step 5),Driver再将执行计划发送给Execution Engine(以下简称EE)。
  4. EE拿到执行计划之后,会发送给合适的组件(step 6.1、6.2、6.3)。Hive的数据存储在HDFS上,所以执行的时候必然要和HDFS打交道。比如要先去NameNode上面查询数据的位置,然后去DataNode上面获取数据。如果是DDL操作的话(比如CREATE、DROP、ALTER等),还要和Hive的MetaStore通信。图中画的是使用MR的情况,MR可能有多个阶段,中间也会生成一些临时文件,这些文件都存储在HDFS上面。如果是DML操作,最后会将临时文件直接重命名(HDFS的重命名是一个原子操作)为最终的表名。如果是查询语句,Driver会调用fetch语句,通过Execution Engine直接从HDFS上面读取临时文件。

四、表类型详解

  1. 表分类

在Hive中,表类型主要分为两种:

内部表: 也叫管理表,表目录会创建在hdfs的/user/hive/warehouse/下的相应的库对应的目录中。

外部表: 外部表会根据创建表时LOCATION指定的路径来创建目录,如果没有指定LOCATION,则位置跟内部表相同,一般使用的是第三方提供的或者公用的数据。

  1. 两者之间区别

内部表和外部表在创建时的差别

内部表

CRAATE TABLE T_INNER(ID INT);

外部表

CREATE EXTERNAL TABLE T_OUTER(ID INT) LOCATION 'HDFS:///AA/BB/CC';

Hive表创建时要做的两件事:

  1. 在HDFS下创建表目录
  2. 在元数据库Mysql创建相应表的描述数据(元数据)

drop时有不同的特性:

  1. drop时,元数据都会被清除
  2. drop时,内部表的表目录会被删除,但是外部表的表目录不会被删除。

使用场景
内部表:平时用来测试或者少量数据,并且自己可以随时修改删除数据。
外部表使用后数据不想被删除的情况使用外部表(推荐)所以,整个数据仓库的最底层的表使用外部表。

Hive 的基本操作

1. 注释语法:

-- 单行注释 
// 单行注释 
/*
 * 多行注释
 */

2. 大小写规则:

Hive的数据库名、表名都不区分大小写
建议关键字大写

3. 命名规则:

  1. 名字不能使用数字开头
  2. 不能使用关键字
  3. 尽量不使用特殊符号
  4. 如果表比较多,那么表名和字段名可以定义规则加上前缀.

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

  1. load方式读文件
-- 从hdfs中加载数据 
hive> load data inpath 'hivedata/user.csv' into table user; 

-- 从本地加载数据 
hive> load data local inpath 'hivedata/user.csv' into table user;

加载数据的本质:

  1. 如果数据在本地,加载数据的本质就是将数据copy到hdfs上的表目录下。
  2. 如果数据在hdfs上,加载数据的本质是将数据移动到hdfs的表目录下。
  3. 如果重复加载同一份数据,不会覆盖

注意:

Hive使用的是严格的读时模式:加载数据时不检查数据的完整性,读时发现数据不对则使用NULL来代替。
Mysql使用的是写时模式:在写入数据时就进行检查。

  1. insert into 方式灌入数据
    先创建一个和旧表结构一样的表
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;
  1. 克隆表

不带数据,只克隆表的结构

-- 从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.分区表基本操作

  1. 分区表加载数据
-- 一级分区
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');
  1. 新增分区
alter table part5 add partition(dt='2020-03-21');
  1. 增加分区并设置数据
alter table part5 add partition(dt='2020-11-11') 
location '/user/hive/warehouse/part1/dt=2019-08-08';
  1. 修改分区的hdfs的路径
alter table part5 partition(dt='2020-03-21') 
set location 'hdfs://hadoop01:8020/user/hive/warehouse//part1/dt=2019-09-11'
  1. 删除分区
alter table part5 drop partition(dt='2020-03-24'),partition(dt='2020-03- 26');

4.分区表类型

  1. 静态分区

加载数据到指定分区的值,新增分区或者加载分区时指定分区名

  1. 动态分区

数据未知,根据分区的值来确定需要创建的分区。

动态分区的属性配置
是否能动态分区
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;
  1. 混合分区

静态和动态都有。

创建混合分区表

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. 注意

1.hive的分区使用的是表外字段,分区字段是一个列,但是分区字段是可以做查询
过滤。
2.分区字段不建议使用中文
3.一般不建议使用动态分区,因为动态分区会使用mapreduce来进行查询数据,如果分区数据过多,导致 namenode 和 resourcemanager 的性能瓶颈。所以建议在使用动态分区前尽可能预知分区数量。
4.分区属性的修改都可以使用修改元数据和hdfs数据内容。

五、分桶表

1.分桶的意义
当单个的分区或者表的数据量过大,分区不能更细粒度的划分数据,就需要使用分桶技术将数 据划分成更细的粒度。

2. 关键字及其原理

bucket
分桶的原理:跟MR中的HashPartitioner原理一样,都是key的hash值取模reduce的数量
MR中:按照key的hash值除以reduceTask取余
Hive中:按照分桶字段的hash值取模除以分桶的个数

3.分桶表的操作

  1. 创建
create table t_stu( 
Sno int, 
Sname string, 
Sex string, 
Sage int, 
Sdept string
) 
row format delimited fields terminated by ',' 
stored as textfile; 
  1. 加载数据

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);
  1. 分桶查询

语法:

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; 

你可能感兴趣的:(大数据,hadoop,hive,数据库,mysql)