文章目录
- 第 1 章 Hive 基本概念
- 第 2 章 Hive常用命令
- 第 3 章 Hive 数据类型
- 第 4 章 DDL 数据定义
- 第 5 章 DML 数据操作
- 第 6 章 查询
- 6.2 分组
- 6.3 Join 语句
- 6.4 排序
- 第 7 章 分区表和分桶表
- 第 8 章 函数
- 第九章 压缩和存储
- 第 10 章 企业级调优
第 1 章 Hive 基本概念
1.1 什么是 Hive
1.1.1简介
Hive:由 Facebook 开源用于解决海量结构化日志的数据统计工具。
Hive 是基于 Hadoop 的一个数据仓库工具,可以将结构化的数据文件映射为一张表,并提供类 SQL 查询功能。
1.1.2Hive 本质
将 HQL 转化成 MapReduce 程序
(1)Hive 处理的数据存储在 HDFS
(2)Hive 分析数据底层的实现是 MapReduce
(3)执行程序运行在 Yarn 上
1.2Hive 的优缺点
1.2.1优点
(1) 操作接口采用类 SQL 语法,提供快速开发的能力(简单、容易上手)。
(2) 避免了去写 MapReduce,减少开发人员的学习成本。
(3)Hive 的执行延迟比较高,因此 Hive 常用于数据分析,对实时性要求不高的场合。
(4)Hive 优势在于处理大数据,对于处理小数据没有优势,因为 Hive 的执行延迟比较高。
(5)Hive 支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。
1.2.2缺点
1)Hive 的 HQL 表达能力有限
(1)迭代式算法无法表达
(2)数据挖掘方面不擅长,由于 MapReduce 数据处理流程的限制,效率更高的算法却
无法实现。
2)Hive 的效率比较低
(1)Hive 自动生成的 MapReduce 作业,通常情况下不够智能化
(2)Hive 调优比较困难,粒度较粗
1.3 Hive 架构原理
第一部分才是Hive自己的 第二部分是 Hadoop ,第三部分是 元数据存储的是元数据 HIve中的表 和HDFS中的路径映射 默认存储在derby
为啥修改derby?
原因在于 Hive 默认使用的元数据库为 derby,开启 Hive 之后就会占用元数据库,且不与其他客户端共享数据,所以我们需要将 Hive 的元数据地址改为 MySQL。
1)用户接口:Client
CLI(command-line interface)、JDBC/ODBC(jdbc 访问 hive)、WEBUI(浏览器访问 hive)
jdbc连接数据库的步骤:
1、加载jdbc驱动程序;
2、创建数据库的连接;
3、创建preparedStatement;
4、执行SQL语句;
5、遍历结果集;
6、处理异常,关闭JDBC对象资源。
jdbc中对应Driver驱动 ,只不过是个字符串通过反射找到类构建对象
上面都是客户端干的事情
下面四个才是Hive干的事情
((1)解析器(SQL Parser):将 SQL 字符串将from 找到对应的元数据关系,把准备工作做好
(2)编译器(Physical Plan):真正的翻译成MR任务的执行流程
(3)优化器(Query Optimizer):对逻辑执行计划进行优化。 左边都是小表驱动大表默认优化
(4)执行器(Execution):把逻辑执行计划转换成可以运行的物理计划。对于 Hive 来说,就是 MR/Spark。
1.4 Hive 和数据库比较
由于 Hive 采用了类似 SQL 的查询语言 HQL(Hive Query Language),因此很容易将 Hive 理解为数据库。其实从结构上来看,Hive 和数据库除了拥有类似的查询语言,再无类似之处。本文将从多个方面来阐述 Hive 和数据库的差异。
1.4.1 查询语言
由于 SQL 被广泛的应用在数据仓库中,因此,专门针对 Hive 的特性设计了类 SQL 的查询语言 HQL。熟悉 SQL 开发的开发者可以很方便的使用 Hive 进行开发
1.4.2 数据更新
由于 Hive 是针对数据仓库应用设计的,而数据仓库的内容是读多写少的。因此,Hive 中不建议对数据的改写,所有的数据都是在加载的时候确定好的。
1.4.3 执行延迟
Hive 在查询数据的时候,由于没有索引,需要扫描整个表,因此延迟较高。另外一个导致 Hive 执行延迟高的因素是 MapReduce 框架。由于 MapReduce 本身具有较高的延迟,因此在利用 MapReduce 执行 Hive 查询时,也会有较高的延迟。相对的,数据库的执行延迟较低。当然,这个低是有条件的,即数据规模较小,当数据规模大到超过数据库的处理能力的时候,Hive 的并行计算显然能体现出优势。
1.4.4 数据规模
由于 Hive 建立在集群上并可以利用 MapReduce 进行并行计算,因此可以支持很大规模的数据;对应的,数据库可以支持的数据规模较小。
第 2 章 Hive常用命令
[atguigu@hadoop102 hive]$ bin/hive -help
usage: hive
-d,–define <key=value> Variable subsitution to apply to hive
commands. e.g. -d A=B or --define A=B
–database Specify the database to use
-e SQL from command line
-f SQL from files
-H,–help Print help information
–hiveconf <property=value> Use value for given property
–hivevar <key=value> Variable subsitution to apply to hive
commands. e.g. --hivevar A=B
-i Initialization SQL file
-S,–silent Silent mode in interactive shell
-v,–verbose Verbose mode (echo executed SQL to the console)
“-e”不进入 hive 的交互窗口执行 sql 语句
bin/hive -e “select id from student;”
“-f”执行脚本中 sql 语句
*touch hivef.sql
select from student;
bin/hive -f /opt/module/hive/datas/hivef.sql
退出 hive 窗口:
hive(default)>exit;
hive(default)>quit;
在 hive cli 命令窗口中如何查看 hdfs 文件系统
hive(default)>dfs -ls /;
3)查看在 hive 中输入的所有历史命令
cat .hivehistory
第 3 章 Hive 数据类型
3.1 基本数据类型
Hive 数据类型 | Java 数据类型 | 长度 | 例子 |
---|---|---|---|
TINYINT | byte | 1byte | 有符号整数 20 |
SMALINT | short | 2byte | 有符号整数 20 |
INT | int | 4byte | 有符号整数 20 |
BIGINT | long | 8byte | 有符号整数 20 |
BOOLEAN | boolean | 布尔类型,true 或者false | TRUE FALSE |
FLOAT | float | 单精度浮点数 | 3.14159 |
DOUBLE | double | 双精度浮点数 | 3.14159 |
STRING | string | 字符系列。可以指定字符集。可以使用单引号或者双引号。 | ‘ now is the time ’“for all good men” |
TIMESTAMP | 时间类型 | ||
BINARY | 字节数组 |
对于 Hive 的 String 类型相当于数据库的 varchar 类型,该类型是一个可变的字符串,不过它不能声明其中最多能存储多少个字符,理论上它可以存储 2GB 的字符数。
3.2 类型转化
Hive 的原子数据类型是可以进行隐式转换的,类似于 Java 的类型转换,例如某表达式
使用 INT 类型,TINYINT 会自动转换为 INT 类型,但是 Hive 不会进行反向转化,例如,某表达式使用 TINYINT 类型,INT 不会自动转换为 TINYINT 类型,它会返回错误,除非使用 CAST操作
1)隐式类型转换规则如下
(1)任何整数类型都可以隐式地转换为一个范围更广的类型,如 TINYINT 可以转换成INT,INT 可以转换成 BIGINT。
(2)所有整数类型、FLOAT 和 STRING
类型都可以隐式地转换成 DOUBLE。
(3)TINYINT、SMALLINT、INT 都可以转换为 FLOAT。
(4)BOOLEAN 类型不可以转换为任何其它的类型。
2)可以使用 CAST 操作显示进行数据类型转换
例如 CAST(‘1’ AS INT)将把字符串’1’ 转换成整数 1;如果强制类型转换失败,如执行CAST(‘X’ AS INT),表达式返回空值 NULL。
第 4 章 DDL 数据定义
4.1 创建数据库
避免要创建的数据库已经存在错误,增加 if not exists 判断。(标准写法)
CREATE DATABASE [IF NOT EXISTS] database_name
创建一个数据库,指定数据库在 HDFS 上存放的位置
create database db_hive2 location '/db_hive2.db';
4.2 查询数据库
4.2.1 显示数据库
1.显示数据库
show databases;
2.过滤显示查询的数据库
hive> show databases like ‘db_hive*’;
OK
db_hive
db_hive_1
4.2.2 查看数据库详情
显示数据库详细信息,extended
hive> desc database extended db_hive;
OK
db_hive hdfs://hadoop102:9820/user/hive/warehouse/db_hive.db atguiguUSER
4.2.3 切换当前数据库
hive (default)> use db_hive;
4.3 修改数据库
用户可以使用 ALTER DATABASE 命令为某个数据库的 DBPROPERTIES 设置键-值对属性值,来描述这个数据库的属性信息。
hive (default)> alter database db_hive
set dbproperties(‘createtime’=‘20170830’);
在 hive 中查看修改结果
hive> desc database extended db_hive;
db_name comment location owner_name owner_type parameters
db_hive hdfs://hadoop102:9820/user/hive/warehouse/db_hive.db
atguigu USER {createtime=20170830}
4.4 删除数据库
4.5.1删除空数据库
drop database db_hive2;
2)如果删除的数据库不存在,最好采用 if exists 判断数据库是否存在
hive> drop database db_hive;
FAILED: SemanticException [Error 10072]: Database does not exist: db_hive
hive> drop database if exists db_hive2;
3)如果数据库不为空,可以采用 cascade 命令,强制删除
hive> drop database db_hive;
FAILED: Execution Error, return code 1 from
org.apache.hadoop.hive.ql.exec.DDLTask. InvalidOperationException(message:Database db_hive is not empty. One or more tables exist.)
hive> drop database db_hive cascade;
4.5 创建表
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]
[LOCATION hdfs_path]
[TBLPROPERTIES (property_name=property_value, ...)]
[AS select_statement]
2)字段解释说明
(1)CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXISTS 选项来忽略这个异常
(2)EXTERNAL 关键字可以让用户创建一个外部表,在建表的同时可以指定一个指向实际数据的路径(LOCATION),在删除表的时候,内部表的元数据和数据会被一起删除,而外部表只删除元数据,不删除数据
。
(3)COMMENT:为表和列添加注释。
(4)PARTITIONED BY 创建分区表
(5)CLUSTERED BY 创建分桶表
(6)SORTED BY 不常用,对桶中的一个或多个列另外排序
(7)LOCATION :指定表在 HDFS 上的存储位置。
(8)AS:后跟查询语句,根据查询结果创建表。
(9)LIKE 允许用户复制现有的表结构,但是不复制数据。
4.5.1 管理表
默认创建的表都是所谓的管理表,有时也被称为内部表。因为这种表,Hive 会(或多或少地)控制着数据的生命周期。
当我们删除一个管理表时,Hive 也会删除这个表中数据。管理表不适合和其他工具共享数据。
4.5.2 外部表
因为表是外部表,所以 Hive 并非认为其完全拥有这份数据。删除该表并不会删除掉这份数据,不过描述表的元数据信息会被删除掉。
4.5.2.1管理表和外部表的使用场景
每天将收集到的网站日志定期流入 HDFS 文本文件。在外部表(原始日志表)的基础上
做大量的统计分析,用到的中间表、结果表使用内部表存储,数据通过 SELECT+INSERT 进入内部表。
外部表删除后,hdfs 中的数据还在,但是 metadata 中 dept 的元数据已被删除
4.5.3 管理表与外部表的互相转换
alter table student2 set tblproperties('EXTERNAL'='TRUE'); FALSE 则为内部表
4.6 修改表
4.6.1重命名表 | 增加/修改/替换列信息
1)语法
重命名表
ALTER TABLE table_name RENAME TO new_table_name
(1)查询表结构
hive> desc dept;
(2)添加列
hive (default)> alter table dept add columns(deptdesc string);
(4)更新列
hive (default)> alter table dept change column deptdesc desc string;
(6)替换列
hive (default)> alter table dept replace columns(deptno string, dname
string, loc string);
4.7 删除表
hive (default)> drop table dept;
第 5 章 DML 数据操作
5.1数据导入
5.1.1 向表中装载数据(Load)
5.1.1.1语法
hive> load data [local] inpath '数据的 path' [overwrite] into table
student [partition (partcol1=val1,…)];
(1)load data:表示加载数据
(2)local:表示从本地加载数据到 hive 表;否则从 HDFS 加载数据到 hive 表
(3)inpath:表示加载数据的路径
(4)overwrite:表示覆盖表中已有数据,否则表示追加
(5)into table:表示加载到哪张表
(6)student:表示具体的表
(7)partition:表示上传到指定分区
5.1.1.2 案例
(1)加载本地文件到 hive
hive (default)> load data local inpath
‘/opt/module/hive/datas/student.txt’ into table default.student;
(2)加载 HDFS 文件到 hive 中
创建一张表
hive (default)> create table student(id string, name string) row formatdelimited fields terminated by ‘\t’;
上传文件到 HDFS
hive (default)> dfs -put /opt/module/hive/data/student.txt /user/atguigu/hive;
加载 HDFS 上数据
hive (default)> load data inpath ‘/user/atguigu/hive/student.txt’ intotable default.student;
5.1.2 通过查询语句向表中插入数据(Insert)
5.1.2.1 基本模式插入(根据单张表查询结果)
hive (default)> insert overwrite table student_par select id, name from student where month=‘201709’;
和MySQL 很像
insert into:以追加数据的方式插入到表或分区,原有数据不会删除
insert overwrite:会覆盖表中已存在的数据
注意:insert 不支持插入部分字段
5.1.2.2 多表(多分区)插入模式(根据多张表查询结果)
5.1.3 查询语句中创建表并加载数据(As Select)
create table if not exists student3 as select id, name from student;
5.1.4 创建表时通过 Location 指定加载数据路径
hive (default)> create
external
table if not exists student5
( id int, name string)
row format delimited fields terminated by ‘\t’
location
’/student;
这个location是指定在 hdfs位置 ,就是 假如我在里面设置有文件内容在那里可以直接获得中的内容,可以通过select 查到里面数据 ,如果不加 这个student5是没数据的
5.2 数据导出
5.2.1 Insert 导出
2)将查询的结果格式化导出到本地
hive(default)>insert overwrite local directory
‘/opt/module/hive/data/export/student1’
ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘\t’
select * from student;
5.2.2清除表中数据(Truncate)
注意:Truncate 只能删除管理表,不能删除外部表中数据
hive (default)> truncate table student;
第 6 章 查询
6.1 基本查询(Select…From)
SELECT [ALL | DISTINCT] select_expr, select_expr, ...
FROM table_reference
[WHERE where_condition]
[GROUP BY col_list]
[ORDER BY col_list]
[CLUSTER BY col_list
| [DISTRIBUTE BY col_list] [SORT BY col_list]
]
[LIMIT number]
注意:
(1)SQL 语言大小写不敏感。
(2)SQL 可以写在一行或者多行
(3)关键字不能被缩写也不能分行
(4)各子句一般要分行写。
(5)使用缩进提高语句的可读性。
6.1.2 列别名 AS 或者 紧跟列名
6.1.3 常用函数
>1)求总行数(count)
hive (default)> select count(*) cnt from emp;
2)求工资的最大值(max)
hive (default)> select max(sal) max_sal from emp;
3)求工资的最小值(min)
hive (default)> select min(sal) min_sal from emp;
4)求工资的总和(sum)
hive (default)> select sum(sal) sum_sal from emp;
5)求工资的平均值(avg)
hive (default)> select avg(sal) avg_sal from emp;
6.1.4 Limit 语句
6.1.5 Where 语句
A [NOT] BETWEEN B AND C
; 如果 A,B 或者 C 任一为 NULL,则结果为 NULL。如果 A 的值大于等于 B 而且小于或等于 C,则结果为 TRUE,反之为 FALSE。
如果使用 NOT 关键字则可达到相反的效果。
IN(数值 1, 数值 2)
使用 IN 运算显示列表中的值
6.1.8 Like 和 RLike
6.1.8.1 使用 LIKE 运算选择类似的值
6.1.8.2 选择条件可以包含字符或数字:
% 代表零个或多个字符(任意个字符)。
_ 代表一个字符。
6.1.8.3 RLIKE 子句
RLIKE 子句是 Hive 中这个功能的一个扩展,其可以通过 Java 的正则表达式这个更强大
的语言来指定匹配条件。
6.1.8.4 案例
(1)查找名字以 A 开头的员工信息
hive (default)> select * from emp where ename LIKE ‘A%’;
(2)查找名字中第二个字母为 A 的员工信息
hive (default)> select * from emp where ename LIKE ‘_A%’;
(3)查找名字中带有 A 的员工信息
hive (default)> select * from emp where ename RLIKE ‘[A]’;
6.2 分组
6.2.1 Group By 语句
6.2.1.1 案例
(1)计算 emp 表每个部门的平均工资
hive (default)> select t.deptno, avg(t.sal) avg_sal from emp t group by t.deptno;
6.2.2 Having 语句
1)having 与 where 不同点
(1)where 后面不能写分组函数,而 having 后面可以使用分组函数。
(2)having 只用于 group by 分组统计语句。
6.3 Join 语句
6.3.1 等值 Join
Hive 支持通常的 SQL JOIN 语句。
6.3.3 内连接
内连接:只有进行连接的两个表中都存在与连接条件相匹配的数据才会被保留下来。
hive (default)> select e.empno, e.ename, d.deptno
from emp e
join dept d on e.deptno = d.deptno;
6.3.4 左外连接
左外连接:JOIN 操作符左边表中符合 WHERE 子句的所有记录将会被返回。
hive (default)> select e.empno, e.ename, d.deptno
from emp e
left join dept d on e.deptno = d.deptno;
6.3.5 右外连接
右外连接:JOIN 操作符右边表中符合 WHERE 子句的所有记录将会被返回。
hive (default)> select e.empno, e.ename, d.deptno
from emp e
right join dept d on e.deptno = d.deptno;
6.3.6 满外连接
满外连接:将会返回所有表中符合 WHERE 语句条件的所有记录。如果任一表的指定字
段没有符合条件的值的话,那么就使用 NULL 值替代。
hive (default)> select e.empno, e.ename, d.deptno
from emp e
full join dept d on e.deptno = d.deptno;
6.3.7 多表连接
hive (default)>SELECT e.ename, d.dname, l.loc_name
FROM emp e
JOIN dept d
ON d.deptno = e.deptno
JOIN location l
ON d.loc = l.loc;
大多数情况下,Hive 会对每对 JOIN 连接对象启动一个 MapReduce 任务。本例中会首先
启动一个 MapReduce job 对表 e 和表 d 进行连接操作,然后会再启动一个 MapReduce job 将
第一个 MapReduce job 的输出和表 l;进行连接操作。
注意:为什么不是表 d 和表 l 先进行连接操作呢?这是因为 Hive 总是按照从左到右的
顺序执行的。
优化:当对 3 个或者更多表进行 join 连接时**,如果每个 on 子句都使用相同的连接键的
话,那么只会产生一个 MapReduce job。**
6.4 排序
6.4.1 全局排序(Order By)
Order By:全局排序,只有一个 Reducer
6.4.1.1 使用 ORDER BY 子句排序
ASC(ascend): 升序(默认)
DESC(descend): 降序
6.4.3 每个 Reduce 内部排序(Sort By)
Sort By:对于大规模的数据集 order by 的效率非常低。在很多情况下,并不需要全局排
序,此时可以使用 sort by。
Sort by 为每个 reducer 产生一个排序文件。每个 Reducer 内部进行排序,对全局结果集
来说不是排序。
6.4.5 分区(Distribute By)
Distribute By: 在有些情况下,我们需要控制某个特定行应该到哪个 reducer,通常是为
了进行后续的聚集操作。distribute by 子句可以做这件事。distribute by 类似 MR 中 partition
(自定义分区),进行分区,结合 sort by 使用。
对于 distribute by 进行测试,一定要分配多 reduce 进行处理,否则无法看到 distribute
by 的效果。
6.4.5.1案例
6.4.6 Cluster By
当 distribute by 和 sorts by 字段相同时,可以使用 cluster by 方式。
cluster by 除了具有 distribute by 的功能外还兼具 sort by 的功能。但是排序只能是升序
排序,不能指定排序规则为 ASC 或者 DESC。
(1)以下两种写法等价
hive (default)> select * from emp cluster by deptno; hive (default)>
select * from emp distribute by deptno sort by deptno;
注意:按照部门编号分区,不一定就是固定死的数值,可以是 20 号和 30 号部门分到一
个分区里面去。
第 7 章 分区表和分桶表
7.1 分区表
分区表实际上就是对应一个 HDFS 文件系统上的独立的文件夹,该文件夹下是该分区所
有的数据文件。Hive 中的分区就是分目录,把一个大的数据集根据业务需要分割成小的数据
集。在查询时通过 WHERE 子句中的表达式选择查询所需要的指定的分区,这样的查询效率
会提高很多。
7.1.1 分区表基本操作
7.1.1.1创建分区表语法
hive (default)> create table dept_partition(
deptno int, dname string, loc string
)partitioned by (day string)
row format delimited fields terminated by ‘\t’;
注意:分区字段不能是表中已经存在的数据,可以将分区字段看作表的伪列。
分区字段 放在 目录当中 放在 MySQL的 元数据当中 用where的时候定位到 HDFS中数据库的元数据 ,避免全表扫描
7.1.1.2 查询分区表中数据
单分区查询
hive (default)> select * from dept_partition where day='20200401';
7.1.1.3 增加分区
创建单个分区
hive (default)> alter table dept_partition add partition(day='20200404');
同时创建多个分区
hive (default)> alter table dept_partition add partition(day='20200405') partition(day='20200406');
7.1.1.4删除分区
删除单个分区
hive (default)> alter table dept_partition drop partition (day=‘20200406’);
同时删除多个分区
hive (default)> alter table dept_partition
drop partition (day='20200404'), partition(day='20200405');
7.1.1.5查看分区表有多少分区
hive> show partitions dept_partition;
7.1.1.6查看分区表结构
hive> desc formatted dept_partition;
7.1.2 二级分区
1)创建二级分区表
hive (default)> create table dept_partition2(
deptno int, dname string, loc string
)
partitioned by (day string, hour string)
row format delimited fields terminated by '\t';
7.1.3 动态分区调整
关系型数据库中,对分区表 Insert 数据时候,数据库自动会根据分区字段的值,将数据
插入到相应的分区中,Hive 中也提供了类似的机制,即动态分区(Dynamic Partition),只不过,
使用 Hive 的动态分区,需要进行相应的配置。
1)开启动态分区参数设置
(1)开启动态分区功能(默认 true,开启)
hive.exec.dynamic.partition=true
(2)设置为非严格模式(动态分区的模式,默认 strict,表示必须指定至少一个分区为
静态分区,nonstrict 模式表示允许所有的分区字段都可以使用动态分区。)
hive.exec.dynamic.partition.mode=nonstrict
(3)在所有执行 MR 的节点上,最大一共可以创建多少个动态分区。默认 1000
hive.exec.max.dynamic.partitions=1000
(4)在每个执行 MR 的节点上,最大可以创建多少个动态分区。该参数需要根据实际
的数据来设定。比如:源数据中包含了一年的数据,即 day 字段有 365 个值,那么该参数就
需要设置成大于 365,如果使用默认值 100,则会报错。
hive.exec.max.dynamic.partitions.pernode=100
(5)整个 MR Job 中,最大可以创建多少个 HDFS 文件。默认 100000
hive.exec.max.created.files=100000
(6)当有空分区生成时,是否抛出异常。一般不需要设置。默认 false
hive.error.on.empty.partition=false
7.2 分桶表
分区提供一个隔离数据和优化查询的便利方式。不过,并非所有的数据集都可形成合理
的分区。对于一张表或者分区,Hive 可以进一步组织成桶,也就是更为细粒度的数据范围划分。
按照哪个字段 分桶 , 按照id的hash 值 模拟 桶的数量 ,将大数据 进一步划分**(不太重要 )**
第 8 章 函数
8.1 系统内置函数
1)查看系统自带的函数
hive> show functions;
2)显示自带的函数的用法
hive> desc function upper;
3)详细显示自带的函数的用法
hive> desc function extended upper;
8.2 常用内置函数
8.2.1 空字段赋值 NVL
NVL:给值为 NULL 的数据赋值,它的格式是 NVL( value,default_value)。它的功能是如
果 value 为 NULL,则 NVL 函数返回 default_value 的值,否则返回 value 的值,如果两个参数
都为 NULL ,则返回 NULL。
8.2.2 CASE WHEN THEN ELSE END
select
dept_id,
sum(case sex when '男' then 1 when 'a' then 1 else 0 end) male_count,
sum(case sex when '女' then 1 else 0 end) female_count
from emp_sex
group by dept_id;
可以很多1 ,一个case 中 可以有很多when
8.2.3 行转列 (多列变成一列)
CONCAT(string A/col, string B/col…):返回输入字符串连接后的结果,支持任意个输入字
符串;
CONCAT_WS(separator, str1, str2,…):它是一个特殊形式的 CONCAT()。第一个参数剩余参
数间的分隔符。分隔符可以是与剩余参数一样的字符串。如果分隔符是 NULL,返回值也将
为 NULL。这个函数会跳过分隔符参数后的任何 NULL 和空字符串。分隔符将被加到被连接
的字符串之间;
select concat_ws('-','a','b','c') 等同于 select concat('a','-','b','-','c')
注意: CONCAT_WS must be "string or array
COLLECT_SET(col):函数只接受基本数据类型,它的主要作用是将某字段的值进行去重
汇总,产生 Array 类型字段。
select concat_list *from student 出来的是个数组 逗号分隔,
select concat_list *from student 出来的是个数组 逗号分隔, 回取重
8.2.4 列转行(一行变多行)
EXPLODE(col):将 hive 一列中复杂的 Array 或者 Map 结构拆分成多行。
LATERAL VIEW
用法:LATERAL VIEW udtf(expression) tableAlias AS columnAlias
解释:用于和 split, explode 等 UDTF 一起使用,它能够将一列数据拆成多行数据,在此
基础上可以对拆分后的数据进行聚合。
SELECT
movie,
category_name
FROM
movie_info
lateral VIEW
explode(split(category,",")) movie_info_tmp AS category_name;
8.2.5 窗口函数(开窗函数)
1)相关函数说明
OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变而变化。
CURRENT ROW:当前行
n PRECEDING:往前 n 行数据
n FOLLOWING:往后 n 行数据
UNBOUNDED:起点,
UNBOUNDED PRECEDING 表示从前面的起点,
UNBOUNDED FOLLOWING 表示到后面的终点
LAG(col,n,default_val):往前第 n 行数据
LEAD(col,n, default_val):往后第 n 行数据
NTILE(n):把有序窗口的行分发到指定数据的组中,各个组有编号,编号从 1 开始,对
于每一行,NTILE 返回此行所属的组的编号。注意:n 必须为 int 类型。
select count(*) over (partition by name order by orderdate ) from business;
select count(*) over (distribute by name sort by orderdate ) from business;
8.2.6 Rank
RANK() 排序相同时会重复,总数不会变
DENSE_RANK() 排序相同时会重复,总数会减少
ROW_NUMBER() 会根据顺序计算
第九章 压缩和存储
9.1概述
1)压缩的好处和坏处
压缩的优点:以减少磁盘IO、减少磁盘存储空间。
压缩的缺点:增加CPU开销。
2)压缩原则
(1)运算密集型的Job,少用压缩
(2)IO密集型的Job,多用压缩
9.2压缩方式选择
压缩方式选择时重点考虑:压缩/解压缩速度、压缩率(压缩后存储大小)、压缩后是否可以支持切片。
Gzip压缩 | Bzip2压缩 | Lzo压缩 | Snappy压缩 |
---|---|---|---|
优点:压缩率比较高; | 压缩率高;支持Split; | 压缩/解压速度比较快;支持Split; | 优点:压缩和解压缩速度快; |
缺点:不支持Split;压缩/解压速度一般; | 压缩/解压速度慢 | 压缩率一般;想支持切片需要额外创建索引。 | 缺点:不支持Split;压缩率一般 |
9.3 文件存储格式
9.3.1 列式存储和行式存储
如图所示左边为逻辑表,右边第一个为行式存储,第二个为列式存储。
1)行存储的特点
查询满足条件的一整行数据的时候,列存储则需要去每个聚集的字段找到对应的每个列的值,行存储只需要找到其中一个值,其余的值都在相邻地方,所以此时行存储查询的速度更快。
2)列存储的特点
因为每个字段的数据聚集存储,在查询只需要少数几个字段的时候,能大大减少读取的数据量;每个字段的数据类型一定是相同的,列式存储可以针对性的设计更好的设计压缩算法。
4)存储方式和压缩总结
在实际的项目开发当中,hive 表的数据存储格式一般选择:orc 或 parquet。压缩方式一般选择 snappy,lzo。
第 10 章 企业级调优
10.1 执行计划(Explain)
10.1.1 基本语法
EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query
没MR的
explain select * from emp;
有MR的
explain select deptno, avg(sal) avg_sal from emp group by deptno;
(2)查看详细执行计划
explain extended select * from emp;
10.2 Fetch 抓取
Fetch 抓取是指,Hive 中对某些情况的查询可以不必使用 MapReduce 计算
。例如:SELECT
- FROM employees;在这种情况下,Hive 可以简单地读取 employee 对应的存储目录下的文件,
然后输出查询结果到控制台。
在 hive-default.xml.template 文件中 hive.fetch.task.conversion 默认是 more,老版本 hive 默认是minimal,该属性修改为 more 以后,在全局查找、字段查找、limit 查找等都不走 mapreduce
。
设置成 none,然后执行查询语句,都会执行 mapreduce程序。
10.3 本地模式
Hive 可以通过本地模式在单台机器上处理所有的任务。对于小数据集,执行时间可以明显被缩短。
10.4 表的优化
10.4.1 小表大表 Join(MapJOIN)
将 key 相对分散,并且数据量小的表放在 join 的左边,可以使用 map join 让小的维度表先进内存。在 map 端完成 join。
实际测试发现:新版的 hive 已经对小表 JOIN 大表和大表 JOIN 小表进行了优化。小表放在左边和右边已经没有区别。
什么是小表 默认25M以下
10.4.2 大表 Join 大表
10.4.2.1 空 KEY 过滤 不要空 KEY
有时 join 超时是因为某些 key 对应的数据太多,而相同 key 对应的数据都会发送到相同的 reducer 上,从而导致内存不够。此时我们应该仔细分析这些异常的 key,很多情况下,这些 key 对应的数据是异常数据,我们需要在 SQL 语句中进行过滤。例如 key 对应的字段为空
10.4.2.2空 key 转换 要 空 KEY
有时虽然某个 key 为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join 的结果中,此时我们可以表 a 中 key 为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的 reducer 上。
随机分布空 null 值
insert overwrite table jointable
select n.* from nullidtable n full join bigtable o on
nvl(n.id,rand()) = o.id;
消除了数据倾斜,负载均衡 reducer 的资源消耗
10.4.2.3 分桶去JOIN
就是将表数据分成不同文件,将对应的文件一起jOIN 就好了
10.4.3 Group By 和Reduce JOIN一样数据倾斜
根据某个字段分组 如果某个Key 频率特别高 数据倾斜
生成的查询计划会有两个 MR Job。第一个 MR Job 中**,Map 的输出
结果会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果**,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
10.4.4 Count(Distinct) 去重统计
数据量小的时候无所谓,数据量大的情况下,由于 COUNT DISTINCT 操作需要用一个Reduce Task 来完成,这一个 Reduce 需要处理的数据量太大,就会导致整个 Job 很难完成,一般 COUNT DISTINCT 使用先 GROUP BY 再 COUNT 的方式替换,但是需要注意 group by 造成的数据倾斜问题
虽然会多用一个 Job 来完成,但在数据量大的情况下,这个绝对是值得的。
10.4.5 笛卡尔积
尽量避免笛卡尔积,join 的时候不加 on 条件,或者无效的 on 条件,Hive 只能使用 1 个reducer 来完成笛卡尔积
10.4.6 行列过滤
列处理:在 SELECT 中,只拿需要的列,如果有分区,尽量使用分区过滤,少用 SELECT *。
行处理:在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在 Where 后面,那么就会先全表关联,之后再过滤,比如:
1)测试先关联两张表,再用 where 条件过滤
hive (default)> select o.id from bigtable b
join bigtable o on o.id = b.id
where o.id <= 10;
Time taken: 34.406 seconds, Fetched: 100 row(s)
就是可能两张表都where
查询复杂 谓词下推会失效)
2)通过子查询后,再关联表
hive (default)> select b.id from bigtable b
join (select id from bigtable where id <= 10) o on b.id = o.id;
Time taken: 30.058 seconds, Fetched: 100 row(s)
10.4.7 分区
详见 7.1 章。
10.4.8 分桶
详见 7.2 章。
10.5 合理设置 Map 及 Reduce 数
1)通常情况下,作业会通过 input 的目录产生一个或者多个 map 任务。
主要的决定因素有:input 的文件总个数,input 的文件大小,集群设置的文件块大小。
2)是不是 map 数越多越好?
答案是否定的。如果一个任务有很多小文件(远远小于块大小 128m),则每个小文件
也会被当做一个块,用一个 map 任务来完成,而一个 map 任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的 map 数是受限的。
3)是不是保证每个 map 处理接近 128m 的文件块,就高枕无忧了?
答案也是不一定。比如有一个 127m 的文件,正常会用一个 map 去完成,但这个文件只
有一个或者两个小字段,却有几千万的记录,如果 map 处理的逻辑比较复杂,用一个 map任务去做,肯定也比较耗时。
针对上面的问题 2 和 3,我们需要采取两种方式来解决:即减少 map 数和增加 map 数;
10.5.1 复杂文件增加 Map 数
当 input 的文件都很大,任务逻辑复杂,map 执行非常慢的时候,可以考虑增加 Map 数,来使得每个 map 处理的数据量减少,从而提高任务的执行效率。
增加 map 的方法为 : 根据 computeSliteSize(Math.max(minSize,Math.min(maxSize,blocksize)))=blocksize=128M
公式,调整 maxSize 最大值。让 maxSize 最大值低于 blocksize 就可以增加 map 的个数。
10.5.2 小文件进行合并
在 map 执行前合并小文件,减少 map 数:CombineHiveInputFormat 具有对小文件进行合并的功能(系统默认的格式)。HiveInputFormat 没有对小文件合并功能。
set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
2)在 Map-Reduce 的任务结束时合并小文件的设置:
在 map-only 任务结束时合并小文件,默认 true
SET hive.merge.mapfiles = true;
在 map-reduce 任务结束时合并小文件,默认 false
SET hive.merge.mapredfiles = true;
合并文件的大小,默认 256M
SET hive.merge.size.per.task = 268435456;
当输出文件的平均大小小于该值时,启动一个独立的 map-reduce 任务进行文件 merge
SET hive.merge.smallfiles.avgsize = 16777216;
10.5.3 合理设置 Reduce 数
10.5.3.1调整 reduce 个数方法一
(1)每个 Reduce 处理的数据量默认是 256MB
(2)每个任务最大的 reduce 数,默认为 1009
(3)计算 reducer 数的公式
N=min(参数 2,总输入数据量/参数 1)
10.5.3.2 调整 reduce 个数方法二
在 hadoop 的 mapred-default.xml 文件中修改设置每个 job 的 Reduce 个数
set mapreduce.job.reduces = 15;
10.5.3.3 reduce 个数并不是越多越好
(1)过多的启动和初始化 reduce 也会消耗时间和资源;
(2)另外,有多少个 reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;
在设置 reduce 个数的时候也需要考虑这两个原则:处理大数据量利用合适的 reduce 数;使单个 reduce 任务处理数据量大小要合适;
10.6 并行执行
Hive 会将一个查询转化成一个或者多个阶段。这样的阶段可以是 MapReduce 阶段、抽样阶段、合并阶段、limit 阶段。或者 Hive 执行过程中可能需要的其他阶段。默认情况下,Hive 一次只会执行一个阶段。不过,某个特定的 job 可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个 job 的执行时间缩短。不过,如果有更多的阶段可以并行执行,那么 job 可能就越快完成。
当然,得是在系统资源比较空闲的时候才有优势,否则,没资源,并行也起不来。
10.7 严格模式
1)分区表一定得使用分区过滤
2)使用 order by 一定得 limit 过滤
3)不能有笛卡尔积
10.8 JVM 重用
针对小文件使用的
开启uber模式,实现JVM重用(计算方向)
默认情况下,每个Task任务都需要启动一个JVM来运行,如果Task任务计算的数据量很小,我们可以让同一个Job的多个Task运行在一个JVM中,不必为每个Task都开启一个JVM。
10.9 压缩
详见第 9 章。
**如果你能从头看到尾 ,恭喜你 Hive已经入门了 ,还有更多知识得等你工作慢慢开发**
加油吧,少年!