Hive 基础教程

12,595 阅读25分钟

前言

Hive 由 Facebook 实现并开源,是基于 Hadoop 的一个数据仓库工具,可以将结构化的数据映射为一张数据库表,并提供 HQL(Hive SQL)查询功能,底层数据是存储在 HDFS 上。Hive的本质是将 SQL 语句转换为 MapReduce 任务运行,使不熟悉 MapReduce 的用户很方便地利用 HQL 处理和计算 HDFS 上的结构化的数据,适用于离线的批量数据计算。

Hive 依赖于 HDFS 存储数据,Hive 将 HQL 转换成 MapReduce 执行,所以说 Hive 是基于 Hadoop 的一个数据仓库工具,实质就是一款基于 HDFS 的 MapReduce计算框架,对存储在 HDFS 中的数据进行分析和管理。

Hive基本概念

Hive简介

为什么使用Hive

直接使用 MapReduce 所面临的问题: 人员学习成本太高 项目周期要求太短 MapReduce 实现复杂查询逻辑开发难度太大为什么要使用 Hive: 更友好的接口:操作接口采用类 SQL 的语法,提供快速开发的能力 更低的学习成本:避免了写 MapReduce,减少开发人员的学习成本 更好的扩展性:可自由扩展集群规模而无需重启服务,还支持用户自定义函数

Hive的特点

优点: 1.可扩展性,横向扩展,Hive 可以自由的扩展集群的规模,一般情况下不需要重启服务横向扩展:通过分担压力的方式扩展集群的规模纵向扩展:一台服务器cpu i7-6700k 4核心8线程,8核心16线程,内存64G => 128G 2.延展性,Hive 支持自定义函数,用户可以根据自己的需求来实现自己的函数 3.良好的容错性,可以保障即使有节点出现问题,SQL 语句仍可完成执行缺点: 1.Hive 不支持记录级别的增删改操作,但是用户可以通过查询生成新表或者将查询结果导入到文件中(当前选择的 hive-2.3.2 的版本支持记录级别的插入操作) 2.Hive 的查询延时很严重,因为 MapReduce Job 的启动过程消耗很长时间,所以不能用在交互查询系统中。 3.Hive 不支持事务(因为不没有增删改,所以主要用来做 OLAP(联机分析处理),而不是 OLTP(联机事务处理),这就是数据处理的两大级别)。

Hive和RDBMS对比

对比项HiveRDBMS
查询语言HQLSQL
数据存储HDFSRaw Device or Local FS
执行器MapreduceExecutor
数据插入支持批量导入和单条插入支持单条或者批量导入
数据操作覆盖追加行级更新删除
处理数据规模
执行延时
分区支持支持
索引0.8之后加入简单索引支持复杂索引
扩展性高(好)有限(查)
数据加载模式读时模式(快)写时模式(慢)
应用场景海量数据查询实时查询

总结:Hive 具有 SQL 数据库的外表,但应用场景完全不同,Hive 只适合用来做海量离线数据统计分析,也就是数据仓库。

Hive架构

图解Hive结构

基本组成

用户接口

CLI,Shell 终端命令行(Command Line Interface),采用交互形式使用 Hive 命令行与 Hive进行交互,最常用(学习,调试,生产)
JDBC/ODBC,是 Hive 的基于 JDBC 操作提供的客户端,用户(开发员,运维人员)通过这连接至 Hive server 服务
Web UI,通过浏览器访问 Hive

Thrift Server

Thrift 是 Facebook 开发的一个软件框架,可以用来进行可扩展且跨语言的服务的开发,Hive 集成了该服务,能让不同的编程语言调用 Hive 的接口

元数据存储

元数据,通俗的讲,就是存储在 Hive 中的数据的描述信息。Hive 中的元数据通常包括:表的名字,表的列和分区及其属性,表的属性(内部表和外部表),表的数据所在目录。

Metastore 默认存在自带的 Derby 数据库中。缺点就是不适合多用户操作,并且数据存储目录不固定。数据库跟着 Hive 走,极度不方便管理。

解决方案:通常存我们自己创建的 MySQL 库(本地 或 远程),Hive 和 MySQL 之间通过 MetaStore 服务交互。

Driver:编译器(Compiler),优化器(Optimizer),执行器(Executor)

Driver 组件完成 HQL 查询语句从词法分析,语法分析,编译,优化,以及生成逻辑执行计划的生成。生成的逻辑执行计划存储在 HDFS 中,并随后由 MapReduce 调用执行

Hive 的核心是驱动引擎, 驱动引擎由四部分组成:
(1) 解释器:解释器的作用是将 HiveSQL 语句转换为抽象语法树(AST)
(2) 编译器:编译器是将语法树编译为逻辑执行计划
(3) 优化器:优化器是对逻辑执行计划进行优化
(4) 执行器:执行器是调用底层的运行框架执行逻辑执行计划

执行流程

HiveQL 通过命令行或者客户端提交,经过 Compiler 编译器,运用 MetaStore 中的元数据进行类型检测和语法分析,生成一个逻辑方案(Logical Plan),然后通过的优化处理,产生一个 MapReduce 任务。

Hive的数据存储

Hive 特性

1.Hive 的存储结构包括数据库、表、视图、分区和表数据等。数据库,表,分区等等都对应 HDFS 上的一个目录。表数据对应 HDFS 对应目录下的文件。2.Hive 中所有的数据都存储在 HDFS 中,没有专门的数据存储格式,因为 Hive 是读模式(Schema On Read),可支持 TextFile,SequenceFile,RCFile 或者自定义格式等3.只需要在创建表的时候告诉 Hive 数据中的列分隔符和行分隔符,Hive 就可以解析数据    Hive 的默认列分隔符:控制符 Ctrl + A,\x01    Hive 的默认行分隔符:换行符 \n4.Hive 中包含以下数据模型:    database:在 HDFS 中表现为${hive.metastore.warehouse.dir}目录下一个文件夹    table:在 HDFS 中表现所属 database 目录下一个文件夹    external table:与 table 类似,不过其数据存放位置可以指定任意 HDFS 目录路径    partition:在 HDFS 中表现为 table 目录下的子目录    bucket:在 HDFS 中表现为同一个表目录或者分区目录下根据某个字段的值进行 hash 散列之后的多个文件    view:与传统数据库类似,只读,基于基本表创建5.Hive 的元数据存储在 RDBMS 中,除元数据外的其它所有数据都基于 HDFS 存储。默认情况下,Hive 元数据保存在内嵌的 Derby 数据库中,只能允许一个会话连接,只适合简单的测试。实际生产环境中不适用,为了支持多用户会话,则需要一个独立的元数据库,使用MySQL 作为元数据库,Hive 内部对 MySQL 提供了很好的支持。

Hive 中的表分为内部表、外部表、分区表和 Bucket表(分桶表)

内部表和外部表的区别:

删除内部表,删除表元数据和数据
删除外部表,删除元数据,不删除数据

内部表和外部表的使用选择:

大多数情况,他们的区别不明显,如果数据的所有处理都在 Hive 中进行,那么倾向于选择内部表,但是如果 Hive 和其他工具要针对相同的数据集进行处理,外部表更合适。使用外部表访问存储在 HDFS 上的初始数据,然后通过 Hive 转换数据并存到内部表中。使用外部表的场景是针对一个数据集有多个不同的 Schema。

通过外部表和内部表的区别和使用选择的对比可以看出来,hive 其实仅仅只是对存储在HDFS 上的数据提供了一种新的抽象。而不是管理存储在 HDFS 上的数据。所以不管创建内部表还是外部表,都可以对 hive 表的数据存储目录中的数据进行增删操作。

分区表和分桶表的区别:

Hive 数据表可以根据某些字段进行分区操作,细化数据管理,可以让部分查询更快。同时表和分区也可以进一步被划分为 Buckets,分桶表的原理和 MapReduce 编程中的HashPartitioner 的原理类似。

分区和分桶都是细化数据管理,但是分区表是手动添加区分,由于 Hive 是读模式,所以对添加进分区的数据不做模式校验,分桶表中的数据是按照某些分桶字段进行 hash 散列形成的多个文件,所以数据的准确性也高很多。

Hive 环境搭建

Hive 安装

(此处省略了Hive的安装,待后续整理,可以在博客中搜索)

Hive 三种连接方式

CLI

进入到 bin 目录下,直接输入命令:

[hadoop@hadoop01 ~]$ hive

补充:
1.上面的 hive 命令相当于在启动的时候执行:hive --service cli
2.使用 hive --help,可以查看 hive 命令可以启动那些服务
3.通过 hive --service serviceName --help 可以查看某个具体命令的使用方式

HiveServer2/beeline

hive-2.3.2 版本中:都需要对 hadoop 集群做如下改变,否则无法使用

第一:修改 hadoop 集群的 hdfs-site.xml 配置文件:
加入一条配置信息,表示启用 webhdfs
<property> <name>dfs.webhdfs.enabled</name> <value>true</value></property> 
第二:修改 hadoop 集群的 core-site.xml 配置文件:加入两条配置信息:表示设置 hadoop的代理用户
<property> <name>hadoop.proxyuser.hadoop.hosts</name> <value>*</value></property>
<property> <name>hadoop.proxyuser.hadoop.groups</name> <value>*</value></property>
 配置解析:hadoop.proxyuser.hadoop.hosts 
配置成*的意义,表示任意节点使用 hadoop 集群的代理用户hadoop 都能访问 hdfs 集群,
hadoop.proxyuser.hadoop.groups 表示代理用户的组所属


接下来,继续做如下两步:

第一步:先启动 hiveserver2 服务:

启动方式,(假如是在 hadoop01上):
启动为前台:hiveserver2启动为后台:nohup hiveserver2 1>/home/hadoop/hiveserver.log 2>/home/hadoop/hiveserver.err &    
或者:nohup hiveserver2 1>/dev/null 2>/dev/null &    
或者:nohup hiveserver2 >/dev/null 2>&1 &
以上 3 个命令是等价的,第一个表示记录日志,第二个和第三个表示不记录日志命令中的 1 和 2 的意义分别是:
1:表示标准日志输出2:表示错误日志输出如果我没有配置日志的输出路径,日志会生成在当前工作目录,默认的日志名称叫做:nohup.xxx 

第二步:然后启动 beeline 客户端去连接:

执行命令:
beeline -u jdbc:hive2://hadoop01:10000 -n hadoop
-u : 指定元数据库的链接信息
-n : 指定用户名和密码

另外还有一种方式也可以去连接:先执行 beeline然后按图所示输入:
!connect jdbc:hive2://hadoop02:10000 
按回车,然后输入用户名,这个用户名就是安装 hadoop 集群的用户名

Hive 的使用

基本使用

1.创建库:create database if not exists mydb;
2.查看库:show databases;
3.切换数据库:use mydb;
4.创建表:create table if not exists t_user(id string, name string) 或 create table t_user(id string, name string) row format delimited fields terminated by ',';
5.查看表列表:show tables;
6.插入数据:insert into table t_user values ('1','huangbo'), ('2','xuzheng'),('3','wangbaoqiang');
7.查询数据:select * from t_user;
8.导入数据:    a) 导入 HDFS 数据:load data inpath '/user.txt' into table t_user;    b) 导入本地数据:load data local inpath '/home/hadoop/user.txt' into table t_user;  
小技能补充:1.进入到用户的主目录,使用命令 cat /home/hadoop/.hivehistory 可以查看到 hive 执行的历史命令2.执行查询时若想显示表头信息时,
请执行命令:    Hive> set hive.cli.print.header=true;
3.hive的执行日志的存储目录在${java.io.tmpdir}/${user.name}/hive.log中,假如使用hadoop用户操作的 hive,
那么日志文件的存储路径为:/temp/hadoop/hive.log

DDL

库操作

创建库

创建库的使用方式:1.创建普通库    create database dbname;2.创建库的时候检查存与否    create databse if not exists dbname;3.创建库的时候带注释    create database if not exists dbname comment 'create my db named dbname';4.创建带属性的库    create database if not exists dbname with dbproperties ('a'='aaa','b'='bbb');    create database if not exists myhive with dbproperties ('a'='aaa','b'='bbb');

查看库

1.查看有哪些数据库    show databases;2.显示数据库的详细属性信息    语法:desc database [extended] dbname;    示例:desc database extended myhive;3.查看正在使用哪个库    select current_database();4.查看创建库的详细语句    show create database mydb;

删除库

删除库操作:    drop database dbname;    drop database if exists dbname; 默认情况下,hive 不允许删除包含表的数据库,有两种解决办法:1.手动删除库下所有表,然后删除库2.使用 cascade 关键字    drop database if exists dbname cascade;    默认情况下就是 restrict    drop database if exists myhive ==== drop database if exists myhive restrict

切换库

切换库操作:
语法:use database_name
实例:use myhive;

表操作

创建表

概念:CREATE TABLE:创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXISTS 选项来忽略这个异常。EXTERNAL:关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION),如果不存在,则会自动创建该目录。Hive 创建内部表时,会将数据移动到数据仓库指向的路径;若创建外部表,仅记录数据所在的路径,不对数据的位置做任何改变。PARTITIONED BY:在 Hive Select 查询中一般会扫描整个表内容,会消耗很多时间做没必要的工作。有时候只需要扫描表中关心的一部分数据,因此建表时引入 partition 概念。个表可以拥有一个或者多个分区,每个分区以文件夹的形式单独存在表文件夹的目录下,分区是以字段的形式在表结构中存在,通过 desc table 命令可以查看到字段存在,但是该字段不存放实际的数据内容,仅仅是分区的表示。    分区建表分为 2 种:        一种是单分区,也就是说在表文件夹目录下只有一级文件夹目录        一种是多分区,表文件夹下出现多文件夹嵌套模式LIKE:允许用户复制现有的表结构,但是不复制数据。    示例:create table tableA like tableB(创建一张 tableA 空表复制 tableB 的结构)COMMENT:可以为表与字段增加描述ROW FORMAT:用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定ROW FORMAT或者 ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的 SerDe,Hive 通过 SerDe 确定表的具体的列的数据。STORED AS:如果文件数据是纯文本,可以使用 STORED AS TEXTFILE,默认也是 textFile 格式,可以通过执行命令 set hive.default.fileformat,进行查看,如果数据需要压缩,使用 STORED AS SEQUENCEFILE。    A、默认格式 TextFile,数据不做压缩,磁盘开销大,数据解析开销大。可结合 gzip、bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,hive 不会对数据进行切分,从而无法对数据进行并行操作    B、SequenceFile 是 Hadoop API 提供的一种二进制文件支持,文件内容是以序列化的 kv对象来组织的,其具有使用方便、可分割、可压缩的特点。 SequenceFile 支持三种压缩选择:NONE,RECORD,BLOCK。Record 压缩率低,一般建议使用 BLOCK 压缩    C、RCFILE 是一种行列存储相结合的存储方式。首先,其将数据按行分块,保证同一个record 在一个块上,避免读一个记录需要读取多个 block。其次,块数据列式存储,有利于数据压缩和快速的列存取。相比 TEXTFILE 和 SEQUENCEFILE,RCFILE 由于列式存储方式,数据加载时性能消耗较大,但是具有较好的压缩比和查询响应。数据仓库的特点是一次写入、多次读取,因此,整体来看,RCFILE 相比其余两种格式具有较明显的优势CLUSTERED BY:对于每一个表(table)或者分区,Hive 可以进一步组织成桶,也就是说桶是更为细粒度的数据范围划分。Hive 也是针对某一列进行桶的组织。Hive 采用对列值哈希,然后除以桶的个数求余的方式决定该条记录存放在哪个桶当中。    把表(或者分区)组织成桶(Bucket)有两个理由:        (1)获得更高的查询处理效率。桶为表加上了额外的结构,Hive 在处理有些查询时能利用这个结构。具体而言,连接两个在(包含连接列的)相同列上划分了桶的表,可以使用 Map 端连接(Map Join)高效的实现。比如 JOIN 操作。对于 JOIN 操作两个表有一个相同的列,如果对这两个表都进行了桶操作。那么将保存相同列值的桶进行 JOIN操作就可以,可以大大较少 JOIN 的数据量。        (2)使取样(Sampling)更高效。在处理大规模数据集时,在开发和修改查询的阶段,如果能在数据集的一小部分数据上试运行查询,会带来很多方便。LOCATION:指定数据文件存放的 HDFS 目录,不管内部表还是外表,都可以指定。不指定就在默认的仓库路径。    最佳实践:        如果创建内部表请不要指定 location        如果创建表时要指定 location,请创建外部表。   示例:1.创建内部表    create table mytable (id int, name string)row format delimited fields terminated by ',' stored as textfile;2.创建外部表    create external table mytable (id int, name string) row format delimited fields terminated by ',' location '/user/hive/warehouse/mytable2';3.创建分区表    create table mytable (id int, name string) partitioned by(sex string) row format delimited fields terminated by ',' stored as textfile;    插入数据        插入男分区数据:load data local inpath '/root/hivedata/mingxing.txt' overwrite into table mytable partition(sex='boy');        插入女分区数据:load data local inpath '/root/hivedata/mingxing.txt' overwrite into table mytable partition(sex='girl');        查询表分区:show partitions mytable4.创建分桶表    create table stu_buck(Sno int,Sname string,Sex string,Sage int,Sdept string) clustered by(Sno) sorted by(Sno DESC) into 4 buckets row format delimited fields terminated by ',';5.使用like关键字拷贝表// 不管老表是内部表还是外部表,new_table 都是内部表create table new_table like mytable;// 不管老表是内部表还是外部表,如果加 external 关键字,new_table 都是外部表create external table if not exists new_table like mytable;

修改表

  • 重命名表
alter table stu rename to student;
  • 修改表属性
alter table table_name set TBLPROPERTIES ('comment' = 'my new students table');不支持修改表名,和表的数据存储目录
  • 修改 SerDe 信息
更改列分隔符:alter table student set SERDEPROPERTIES ('field.delim' = '-');
  • 增加/删除/改变/替换列
alter table student add columns (course string);alter table student change column id ids int;alter tsble student replace columns (id int,name string,address string);
  • 增加/删除分区
添加分区示例:// 不指定分区路径,默认路径ALTER TABLE student ADD partition(part='a') partition(part='b'); // 指定分区路径ALTER TABLE student ADD IF NOT EXISTS partition(part='bb') location '/myhive_bb' partition(part='cc') location '/myhive_cc'; // 修改分区路径示例ALTER TABLE student partition (part='bb') SET location '/myhive_bbbbb'; // 删除分区示例ALTER TABLE student DROP if exists partition(part='aa');ALTER TABLE student DROP if exists partition(part='aa') if exists partition(part='bb'); 最后补充:1.防止分区被删除:alter table student_p partition (part='aa') enable no_drop;2.防止分区被查询:alter table student_p partition (part='aa') enable offline;enabledisable 是反向操作

删除表

drop table if exists mytable;

清空表

truncate table student;truncate table student partition(city=’beijing’);

其他辅助命令

show databases;
show databases like 'my*';
查看数据库列表
show tables
show tables in myhive;
查看数据表
show create table student;查看数据表的建表语句
show funcations;查看hive函数列表
show partitions student;
show partitions student partition(city='shanghai')
查看hive表分区

desc student;
desc extended student;

desc formatted student;

查看表的详细信息(元数据信息)

desc database student;

desc database extended student;

查看数据库的详细属性
truncate table student; 清空数据表

DML

Load 加载数据

说明:

1.LOAD 操作只是单纯的复制或者移动操作,将数据文件移动到 Hive 表对应的位置。2.LOCAL 关键字    如果指定了 LOCAL, LOAD 命令会去查找本地文件系统中的 filepath。    如果没有指定 LOCAL 关键字,则根据 inpath 中的 uri 查找文件    注意:uri 是指 hdfs 上的路径,分简单模式和完整模式两种,例如:    简单模式:/user/hive/project/data1    完整模式:hdfs://namenode_host:9000/user/hive/project/data13.filepath:    相对路径,例如:project/data1     绝对路径,例如:/user/home/project/data1     包含模式的完整 URI,列如:hdfs://namenode_host:9000/user/home/project/data1    注意:inpath 子句中的文件路径下,不能再有文件夹。4.overwrite 关键字    如果使用了 OVERWRITE 关键字,则目标表(或者分区)中的内容会被删除,然后再将    filepath 指向的文件/目录中的内容添加到表/分区中。    如果目标表(分区)已经有一个文件,并且文件名和 filepath 中的文件名冲突,那么现    有的文件会被新文件所替代。

具体实例:

1.加载本地相对路径数据    load data local inpath '/student.txt' into table student;2.加载绝对路径数据    load data local inpath '/hadoop/data/student.txt' into table student;3.加载绝对路径数据    load data local inpath 'hdfs://192.168.10.201:9000/hadoop/data/student.txt' into table student;4.overwrite 关键字使用    load data local inpath '/student.txt' overwrite into table student;

Insert 插入数据

语法结构:

1.插入一条数据:    INSERT INTO TABLE table_name VALUES(XX,YY,ZZ);2.利用查询语句将结果导入新表:    INSERT OVERWRITE [INTO] TABLE table_name [PARTITION (partcol1=val1, partcol2=val2 ...)]     select_statement1 FROM from_statement3.多重插入    FROM from_statement     INSERT OVERWRITE TABLE table_name1 [PARTITION (partcol1=val1, partcol2=val2 ...)]     select_statement1     INSERT OVERWRITE TABLE table_name2 [PARTITION (partcol1=val1, partcol2=val2 ...)]     select_statement2] ...4.分区插入    分区插入有两种,一种是静态分区,另一种是动态分区。如果混合使用静态分区和动态分区,则静态分区必须出现在动态分区之前。现分别介绍这两种分区插入。静态分区:    A)创建静态分区表    B)从查询结果中导入数据    C)查看插入结果动态分区:    静态分区需要创建非常多的分区,那么用户就需要写非常多的 SQL!Hive 提供了一个动态分区功能,其可以基于查询参数推断出需要创建的分区名称。    A)创建分区表,和创建静态分区表是一样的    B)参数设置        hive> set hive.exec.dynamic.partition=true;        hive> set hive.exec.dynamic.partition.mode=nonstrict;(注意:动态分区默认情况下是开启的。但是却以默认是”strict”模式执行的,在这种模式下要求至少有一列分区字段是静态的。这有助于阻止因设计错误导致查询产生大量的分区。但是此处我们不需要静态分区字段,估将其设为 nonstrict。)对应还有一些参数可设置:    set hive.exec.max.dynamic.partitions.pernode=100; //每个节点生成动态分区最大个数    set hive.exec.max.dynamic.partitions=1000; //生成动态分区最大个数,如果自动分区数大于这个参数,将会报错    set hive.exec.max.created.files=100000; //一个任务最多可以创建的文件数目    set dfs.datanode.max.xcievers=4096; //限定一次最多打开的文件数    set hive.error.on.empty.partition=false; //表示当有空分区产生时,是否抛出异常    (小技能补充:如果以上参数被更改过,想还原,请使用 reset 命令执行一次即可)5.CTAS(create table … as select …)    CREATE TABLE mytest AS SELECT name, age FROM test;    注意:CTAS 操作是原子的,因此如果 select 查询由于某种原因而失败,新表是不会创建的!   

示例:

from mingxing insert into table mingxing2 select id,name,sex,ageinsert into table mingxing select id,name,sex ,age,department ;从 mingxing 表中,按不同的字段进行查询得的结果分别插入不同的 hive 表 from student insert into table ptn_student partition(city='MA') select id,name,sex,age,department where department='MA'insert into table ptn_student partition(city='IS') select id,name,sex,age,department where department='IS';insert into table ptn_student partition(city='CS') select id,name,sex,age,department where department='CS'; 动态数据插入:// 一个分区字段:insert into table test2 partition (age) select name,address,school,age from students;// 多个分区字段:insert into table student_ptn2 partition(city='sa',zipcode) select id, name, sex, age,department, department as zipcode from studentss;

Insert 导出数据

语法结构:

单模式导出:INSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement 多模式导出:FROM from_statementINSERT OVERWRITE [LOCAL] DIRECTORY directory1 select_statement1[INSERT OVERWRITE [LOCAL] DIRECTORY directory2 select_statement2] ...

具体实例:

1.导出数据到本地:    insert overwrite local directory '/home/hadoop/student.txt' select * from students;    (注意:数据写入到文件系统时进行文本序列化,且每列用^A 来区分,\n 为换行符。用more 命令查看时不容易看出分割符,可以使用: sed -e 's/\x01/\t/g' filename 来查看。)2.导出数据到 HDFS    insert overwrite directory '/student' select * from studentss where age >= 20;    insert overwrite directory 'hdfs://hadoop02:9000/user/hive/warehouse/mystudent' select * from studentss;3.导出数据到hdfs,并制定分隔符    默认情况下,hive表导出的列分隔符是^A作为列的分隔符,但是此分隔符显示的不直观,为此hive可以指定列分隔符,我们导出hive表中数据以“\t”为分隔符。    insert overwrite directory '/student.txt' row format delimited fields terminated by "\t" select * from student; 

Select 查询数据

Hive 中的 SELECT 基础语法和标准 SQL 语法基本一致,支持 WHERE、DISTINCT、GROUP BY、ORDER BY、HAVING、LIMIT、子查询等;

  1. select * from db.table1
  2. select count(distinct uid) from db.table1
  3. 支持 select、union all、join(left、right、full join)、like、where、having、各种聚合函数、支持 json 解析
  4. UDF(User Defined Function)/ UDAF/UDTF
  5. 不支持 update 和 delete
  6. hive 虽然支持 in/exists(老版本是不支持的),但是 hive 推荐使用 semi join 的方式来代替实现,而且效率更高。
  7. 支持 case … when …

说明:

1. select_ condition 查询字段2.table_name 表名3.order by(字段) 全局排序,因此只有一个 reducer,只有一个 reduce task 的结果,比如文件名是 000000_0,会导致当输入规模较大时,需要较长的计算时间。4.sort by(字段) 局部排序,不是全局排序,其在数据进入 reducer 前完成排序。因此,如果用 sort by 进行排序,并且设置 mapred.reduce.tasks>1,则 sort by 只保证每个 reducer的输出有序,不保证全局有序。5.distribute by(字段) 根据指定的字段将数据分到不同的 reducer,且分发算法是 hash 散列。6.cluster by(字段) 除了具有 Distribute by 的功能外,还会对该字段进行排序。    因此,如果分桶和 sort 字段是同一个时,此时,cluster by = distribute by + sort by,如果我们要分桶的字段和要排序的字段不一样,那么我们就不能使用 clustered by ,分桶表的作用:最大的作用是用来提高 join 操作的效率. 

具体实例:

1.获取年龄大的三个学生    select id, age,name from student where stat_date= '20140101' order by age desc limit 3;2.查询学生年龄按降序排序    set mapred.reduce.tasks=4;    select id, age, name from student sort by age desc;    select id, age, name from student order by age desc;    select id, age, name from student distribute by age;     分桶和排序的组合操作,对 id 进行分桶,对 age,id 进行降序排序    insert overwrite directory '/root/outputdata6' select * from mingxing2 distribute by id sort by age desc, id desc;     分桶操作,按照 id 分桶,但是不进行排序    insert overwrite directory '/root/outputdata4' select * from mingxing2 distribute by id sort by age;     分桶操作,按照 id 分桶,并且按照 id 排序    insert overwrite directory '/root/outputdata3' select * from mingxing2 cluster by id;     分桶查询:    指定开启分桶:    set hive.enforce.bucketing = true; // 在旧版本中需要开启分桶查询的开关    指定 reducetask 数量,也就是指定桶的数量    set mapreduce.job.reduces=4;    insert overwrite directory '/root/outputdata3' select * from mingxing2 cluster by id;3.按学生名称汇总学生年龄    select name, sum(age) from student group by name;

总结:

一、解释三个执行参数    In order to change the average load for a reducer (in bytes):        set hive.exec.reducers.bytes.per.reducer=<number>    In order to limit the maximum number of reducers:        set hive.exec.reducers.max=<number>    In order to set a constant number of reducers:        set mapreduce.job.reduces=<number>    1.直接使用不带设置值得时候是可以查看到这个参数的默认值:        set hive.exec.reducers.bytes.per.reducer        hive.exec.reducers.bytes.per.reducer:一个 hive,就相当于一次 hive 查询中,每一个reduce 任务它处理的平均数据量        如果要改变值,我们使用这种方式:        set hive.exec.reducers.bytes.per.reducer=51200000    2.查看设置的最大 reducetask 数量        set hive.exec.reducers.max        hive.exec.reducers.max:一次 hive 查询中,最多使用的 reduce task 的数量我们可以这样使用去改变这个值:        set hive.exec.reducers.max = 20    3.查看设置的一个 reducetask 常量数量        set mapreduce.job.reduces        mapreduce.job.reduces:我们设置的 reducetask 数量二、HQL 是否被转换成 MR 的问题    前面说过,HQL 语句会被转换成 MapReduce 程序执行,但是上面的例子可以看出部分HQL 语句并不会转换成 MapReduce,那么什么情况下可以避免转换呢?    1.select * from student; // 简单读取表中文件数据时不会    2.where 过滤条件中只是分区字段时不会转换成 MapReduce    3.set hive.exec.mode.local.auto=true; // hive 会尝试使用本地模式执行    否则,其他情况都会被转换成 MapReduce 程序执行

Hive Join 查询

Hive 支持等值连接(equality join)、外连接(outer join)和(left/right join)。Hive 不支持非等值的连接,因为非等值连接非常难转化到 map/reduce 任务。另外,Hive 支持多于 2 个表的连接。

写查询时要注意以下几点:

1. 只支持等值链接,支持 and,不支持 or
例如:
SELECT a.* FROM a JOIN b ON (a.id = b.id)
SELECT a.* FROM a JOIN b ON (a.id = b.id AND a.department = b.department)
是正确的;
然而:SELECT a.* FROM a JOIN b ON (a.id>b.id)是错误的。

2.可以 join 多于 2 个表
例如:SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
如果 join 中多个表的 join key 是同一个,则 join 会被转化为单个 map/reduce 任务,例如:
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
被转化为单个 map/reduce 任务,因为 join 中只使用了 b.key1 作为 join key。
例如:SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2),而这一 join 被转化为 2 个 map/reduce 任务。因为 b.key1 用于第一次 join 条件,而b.key2 用于第二次 join。

3.Join 时,每次 map/reduce 任务的逻辑
reducer 会缓存 join 序列中除了最后一个表的所有表的记录,再通过最后一个表将结果序列化到文件系统。这一实现有助于在 reduce 端减少内存的使用量。实践中,应该把最大的那个表写在最后(否则会因为缓存浪费大量内存)。例如:
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
所有表都使用同一个 join key(使用 1 次 map/reduce 任务计算)。Reduce 端会缓存 a 表和 b 表的记录,然后每次取得一个 c 表的记录就计算一次 join 结果,类似的还有:
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2)
这里用了 2 次 map/reduce 任务:
第一次缓存 a 表,用 b 表序列化;
第二次缓存第一次 map/reduce 任务的结果,然后用 c 表序列化。

4.HiveJoin 分三种:inner join, outer join, semi join
其中:outer join 包括 left join,right join 和 full outer join,主要用来处理 join 中空记录的情况

a)inner join(内连接)(把符合两边连接条件的数据查询出来)    select * from tablea a inner join tableb b on a.id=b.id; b)left join(左连接,等同于 left outer join)    1.以左表数据为匹配标准,左大右小    2.匹配不上的就是 null    3.返回的数据条数与左表相同    HQL 语句:select * from tablea a left join tableb b on a.id=b.id; c)right join(右连接,等同于 right outer join)    1.以右表数据为匹配标准,左小右大    2.匹配不上的就是 null    3.返回的数据条数与右表相同    HQL 语句:select * from tablea a right join tableb b on a.id=b.id; d)left semi join(左半连接)(因为 hive 不支持 in/exists 操作(1.2.1 版本的 hive 支持in 的操作),所以用该操作实现,并且是 in/exists 的高效实现)    select * from tablea a left semi join tableb b on a.id=b.id; e)full outer join(完全外链接)    select * from tablea a full outer join tableb b on a.id=b.id;