Hive是构建在Hadoop HDFS上的一个数据仓库,可以将结构化的数据文件映射为一张数据库表,并提供类SQL查询功能,其本质是将SQL转换为MapReduce程序。
数据仓库是一个面向主题的、集成的、不可更新的、随时间变化的数据集合,它用于支持企业或组织的决策分析处理。
Hive的表其实就是HDFS的目录/文件。
1.Hive的体系结构
Hive默认采用的是Derby数据库进行元数据的存储(metastore),也支持mysql数据库。Hive中的元数据包括表的名字,表的列和分区及其属性,表的属性,表的数据所在目录等。
2.HQL的执行过程
解释器、编译器、优化器完成HQL查询语句从词语分析、语法分析、编译、优化以及查询计划的生成。生成的查询计划存储在HDFS中,并在随后的MapReduce调用执行。
3.Hive安装的三种模式
1.嵌入模式,数据存储在hive自带的derby数据库,只允许一个连接,多用于本地演示demo;
2.本地模式,一般是mysql,与hive位于同一台服务器,允许多连接,但实际生产环境并不用这种模式;
3.远程模式,mysql安装在远程服务器上,允许多连接,多用于实际生产环境。
4.Hive的数据类型
1)基本数据类型
整型:tinyint/smallint/int/bigint
浮点型:float/double
布尔型:Boolean
字符串:string
2)复杂数据类型
数组类型:Array,有一系列相同数据类型的元素组成
集合类型:Map,包括key->value键值对,可以通过key值访问元素
结构类型:struct,可以包含不同数据类型的元素,可以通过“点语法”的方式获得这些元素
3)时间类型
Date
Timestamp
5.hive与关系型数据库的不同
1) hive和关系数据库存储文件的系统不同,hive使用的是hadoop的HDFS(hadoop的分布式文件系统),关系数据库则是服务器本地的文件系统;
2) hive使用的计算模型是mapreduce,而关系数据库则是自己设计的计算模型;
3) 关系数据库都是为实时查询的业务进行设计的,而hive则是为海量数据做数据挖掘设计的,实时性很差;实时性的区别导致hive的应用场景和关系数据库有很大的不同;
4) Hive很容易扩展自己的存储能力和计算能力,这个是继承hadoop的,而关系数据库在这个方面要比数据仓库差很多。
6.Hive的管理
1)命令行方式(CLI方式)
--hive
--hive --service ci
2)web界面方式
端口号:9999
启动方式:hive --service hwi &
通过浏览器访问:http://<IP地址>:9999/hwi/
3)远程服务访问
一个表可以有一个或者多个分区列,Hive将会为分区列上的每个不同的值组合创建单独的数据目录。分区列是虚拟列,要避免分区列名和数据列名相同,可以基于分区列进行查询。
7.表的介绍
Hive数据表可以细分为一下几种:内部表,外部表,分区表,桶表
内部表
如果在创建表时不指定external关键字,则默认的是创建管理表(内部表),内部表对应的目录必须存储在hive的数据仓库中。
Hive 创建内部表时,会将数据移动到数据仓库指向的路径;
hive>create table tt (name string , age string);
//此时会在hdfs的/user/hive/warehouse/目录下新建一个tt表的数据存放地
hive>load data inpath '/input/data' into table tt;
//接着上传hdfs数据到表中,此时会将hdfs上的/input/data目录下的数据转移到/user/hive/warehouse/下,而/input/data目录下的数据就没有了
注意:删除tt表后,会将tt表的数据和元数据信息全部删除,即/user/hive/warehouse/下没有数据。
特别注意:load data会转移数据,也就是/input/data目录下的数据被转移就没有了。
若创建外部表,仅记录数据所在的路径, 不对数据的位置做任何改变。
hive>create external table et (name string , age string);
//在hdfs的/user/hive/warehouse/下面新建一个表目录et
hive>load data inpath '/input/edata' into table et;
//加载hdfs数据,此时会把hdfs上/input/edata/下的数据转到/user/hive/warehouse/et下
删除这个外部表后,/user/hive/warehouse/et下的数据不会被删除,但是/input/edata/下的数据在上一步load后就已经没有了。数据的位置发生变化,本质是load一个hdfs上的数据时会转移数据。
在删除表的时候,内部表的元数据和数据会被一起删除, 而外部表只删除元数据,不删除数据。这样外部表相对来说更加安全些,数据组织也更加灵活,方便共享源数据。
内部表也称为受控表,表中的数据受表定义影响,表删除后表中数据随之删除。在COLUMNS_V2表中TBL_TYPE显示为MANAGED_TABLE
在http://node01:50070/可以看到表信息
表删除后实际上是从hdfs上将tt目录移到回收站中,另外删除TBLS表中的表定义信息
hive> drop table tt;
Moved:'hdfs://node01:9000/user/hive/warehouse/tt' to trash at:hdfs://node01:9000/user/root/.Trash/Current
OK
Time taken: 1.789 seconds
外部表
数据不受表定义影响,表删除后数据仍在。
hive>create external tab
[root@node01 data]# more t4_hql.hql
create external table t4_exter1(
id string,name string)
row format delimited
fields terminated by '\t' location'hdfs://node01:9000/data/';
hive> source /usr/local/data/t4_hql.hql;
在TBLS表中可以看到外部表信息
也可以在创建表时不指定数据,之后通过alter指定数据
alter table t4_exter1 set location'hdfs://shb01:9000/data/t4';
hive> drop table t4_exter1;
OK
Time taken: 0.274 seconds
外部表只是对数据的引用,如果删除(外部表位置/data/目录下)外部表data/t4的数据不会被删除,hdfs中/user/hive/warehouse目录下的信息不会被删除,而删除的只是TBLS表中的表定义信息。
实际中当系统只有一份公共数据但是多个数据组都需要使用时为避免误删除就需要使用外部表。
内部表和外部表之间还可以互相转换,但是这是个非常危险的操作应尽量避免。
alter table t2 set tblproperties('EXTERNAL'='TRUE');
alter table t2 settblproperties('EXTERNAL'='FALSE');
补充:
(1)加上location用法一样,只不过表目录的位置不同而已。
(2)加上partition用法也一样,只不过表目录下会有分区目录而已。
(3)load data local inpath直接把本地文件系统的数据上传到hdfs上,有location上传到location指定的位置上,没有的话上传到hive默认配置的数据仓库中。
分区表
分区表也是内部表,创建表时可以同时为表创建一个或多个分区,这样我们在加载数据时为其指定具体的分区,查询数据时可以指定具体的分区从而提高效率,分区可以理解为表的一个特殊的列。关键字是partitioned。分区表实际上是将表文件分成多个有标记的小文件方便查询。
分区表:在Hive中,表的每一个分区对应表下的相应目录,所有分区的数据都是存储在对应的目录中。比如lin_test表有start_date分区,则对应start_date=20131218,对应表的目录为/user/hive/warehouse/start_date=20131218/,所有属于这个分区的数据都存放在这个目录中。
如果把一年或者一个月的日志文件存放在一个表下,那么数据量会非常的大,当查询这个表中某一天的日志文件的时候,查询速度还非常的慢,这时候可以采用分区表的方式,把这个表根据时间点再划分为小表。这样划分后,查询某一个时间点的日志文件就会快很多,因为这是不需要进行全表扫描。
hive中的分区表
hive中的分区是根据“分区列”的值对表的数据进行粗略的划分,hive中一个表对应一个目录,再根据分区列在这个表目录下创建子目录,每个子目录名就是分区列的名字。分区列定义与表中字段相似,但是与表中的字段无关,是独立的列。这样就加快了数据查询的速度,因为不会对这个表中进行全盘扫描了。
创建分区表
hive> create table t5_part(id int,namestring)
> partitioned by (year int,city string)
> row format delimited fields terminated by '\t';
OK
Time taken: 0.349 seconds
查看分区表,其中# Partition Information为分区信息,有两个分区year和city
hive> desc extended t5_part;
OK
id int
name string
year int
city string
# Partition Information
# col_name data_type comment
year int
city string
加载数据
第一次分区信息为year=2010, city=BeiJing
hive> load data local inpath'/usr/local/data/t4' into table t5_partpartition(year=2010,city='BeiJing');
Loading data to table default.t5_partpartition (year=2010, city=BeiJing)
Partition default.t5_part{year=2010,city=BeiJing} stats: [numFiles=1, numRows=0, totalSize=13, rawDataSize=0]
OK
Time taken: 3.317 seconds
第二次分区为year=2013, city=ShangHai
hive> load data local inpath'/usr/local/data/t4' into table t5_part partition(year=2013,city='ShangHai');
Loading data to table default.t5_partpartition (year=2013, city=ShangHai)
Partition default.t5_part{year=2013,city=ShangHai} stats: [numFiles=1, numRows=0, totalSize=13, rawDataSize=0]
OK
Time taken: 0.801 seconds
查询全部信息
hive> select * from t5_part;
OK
1 jack 2010 BeiJing
2 tom 2010 BeiJing
1 jack 2013 ShangHai
2 tom 2013 ShangHai
Time taken: 0.165 seconds, Fetched: 4row(s)
根据分区查询,分区很像是一个特殊的列
hive> select * from t5_part whereyear=2010 and city='BeiJing';
OK
1 jack 2010 BeiJing
2 tom 2010 BeiJing
Time taken: 0.112 seconds, Fetched: 2row(s)
分区表加载数据必须指定分区否则会报错
hive> load data local inpath'/usr/local/data/t4' into table t5_part;
FAILED: SemanticException [Error 10062]:Need to specify partition columns because the destination table is partitioned
查看分区表的分区信息
hive> show partitions t5_part;
OK
year=2010/city=BeiJing
year=2013/city=ShangHai
year=2016/city=nanjing
Time taken: 1.685 seconds, Fetched: 3row(s)
hive>
在http://node01:50070下可以看到分区表信息
在hadoop下分区表是把分区当成目录的
其实我觉得分区表在加载数据时就是让数据带着标签入库方便后续大数据量条件下的查询操作。
桶表
之前介绍分区表是将大的表文件划分成多个小文件以利于查询,但是如果数据分布不均衡也会影响查询效率。桶表可以对数据进行哈希取模,目的是让数据能够均匀的分布在表的各个数据文件中,它其实是对分区表的补充。以往查询时需要将数据全部加载到内存中再过滤,而分桶后则可以只将表的部分文件加载到内存中提高查询效率。
分桶表属于内部表,关键字clustered。
hive> sethive.exec.mode.local.auto=true;
hive> set hive.enforce.bucketing=true;
修改参数允许强制分桶,也可以修改hive_site.xml文件中的参数改为true
<property>
<name>hive.enforce.bucketing</name>
<value>false</value>
<description>Whether bucketing is enforced. If true, whileinserting into the table, bucketing is enforced.</description>
</property>
创建分桶表
下面的例子是根据id取模(id%3),into 3 buckets中的3就是取模的值。
hive> create table t6_bucket (id string)clustered by (id) into 3 buckets;
OK
Time taken: 2.773 seconds
加载数据
桶表数据必须从其他表转换
hive> insert into table t6_bucket selectid from t5_part;
可以看到产生3个数据文件,这个过程有一次说明hive是sql解析引擎最终又转化为MapReduce任务。
分别产生了3个文件
下面是hdfs上显示的其中一个文件的内容
[root@node01 data]# hadoop fs -text/user/hive/warehouse/t6_bucket/000001_0
16/12/26 06:50:18 WARNutil.NativeCodeLoader: Unable to load native-hadoop library for yourplatform... using builtin-java classes where applicable
1
1
1
8.Hive的优化
理解Hadoop的核心能力,是hive优化的前提条件,hadoop处理数据的过程有几个显著的特征:
1.不怕数据多,就怕数据倾斜。
2.对jobs数据比较多的作业运行效率相对较低,比如即使有几百行的表,如果多次关联多次汇总,产生十几个jobs,没半小时是跑不完的。map reduce作业初始化的时间是比较长的。
3.对sum,count来说,不存在数据倾斜问题
4.对count(distinct),效率较低,数据量一多,准出问题,如果是多count(distinct)效率更低。
优化可从以下方面着手:
1.好的模型设计事半功倍。
2.解决数据倾斜问题
3.减少job数
4.设置合理的map reduce的task数,能有效提升性能。(比如,10w+级别的计算,用160个reduce,那是相当的浪费,1个足够)。
5.自己动手写sql解决数据倾斜问题是个不错的选择。set hive.groupby.skewindata=true;这是通用的算法优化,但算法优化总是漠视业务,习惯性提供通用的解决方法。ETL开发人员更了解业务,更了解数据,所以通过业务逻辑解决倾斜的方法往往更精确,更有效。
6.对count(distinct)采取漠视的方法,尤其数据大的时候很容易产生倾斜问题,不抱侥幸心理,自己动手。
7.对小文件进行合并,是行之有效的提高调度效率的方法,假如我们的作业设置合理的文件数,对云梯的整体调度效率也会产生积极的影响。
8.优化时把握整体,单个作业最优不如整体最优。