Hive使用
条评论内容:Hive使用
DDL
Data Definition Language,主要的命令有CREATE、ALTER、DROP等。 DDL主要是用在定义、修改数据库对象的结构或数据类型。
数据库操作
Hive有一个默认的数据库default,在操作HQL时,如果不明确的指定要使用哪个库,则使用默认数据库;
Hive的数据库名、表名均不区分大小写;
名字不能使用数字开头;
不能使用关键字,尽量不使用特殊符号;
创建数据库语法
1 | CREATE (DATABASE|SCHEMA) [IF NOT EXISTS] database_name |
示例
1 | -- 创建数据库,在HDFS上存储路径为 /user/hive/warehouse/*.db |
查看数据库
1 | -- 查看所有数据库 |
使用数据库
1 | use mydb; |
删除数据库
1 | -- 删除一个空数据库 |
建表语法
1 | -- 第一种(新建) |
内部表|外部表
在创建表的时候,可指定表的类型。表有两种类型,分别是内部表(管理表)、外部表。
默认情况下,创建内部表。如果要创建外部表,需要使用关键字 external
在删除内部表时,表的定义(元数据) 和数据同时被删除
在删除外部表时,仅删除表的定义,数据被保留在生产环境中,多使用外部表
内部表
数据
1 | 2;zhangsan;book,TV,code;beijing:chaoyang,shagnhai:pudong |
建表
1 | -- 创建内部表 |
外部表
1 | -- 创建外部表 |
内部表与外部表的转换
1 | -- 内部表转外部表 |
分区表
Hive在执行查询时,一般会扫描整个表的数据。由于表的数据量大,全表扫描消耗时 间长、效率低。
而有时候,查询只需要扫描表中的一部分数据即可,Hive引入了分区表的概念,将表的数据存储在不同的子目录中,每一个子目录对应一个分区。只查询部分分区数据 时,可避免全表扫描,提高查询效率。
在实际中,通常根据时间、地区等信息进行分区。
分区表创建与数据加载
1 | -- 创建表 |
备注:分区字段不是表中已经存在的数据,可以将分区字段看成伪列
查看分区
1 | show partitions t3; |
新增分区并设置数据
1 | -- 增加一个分区,不加载数据 |
修改分区的HDFS路径
1 | alter table t3 partition(dt='2020-06-01') set location |
删除分区
1 | -- 可以删除一个或多个分区,用逗号隔开 |
分桶表
当单个的分区或者表的数据量过大,分区不能更细粒度的划分数据,就需要使用分桶技术将数据划分成更细的粒度。将数据按照指定的字段进行分成多个桶中去,即将数据按照字段进行划分,数据按照字段划分到多个文件当中去。分桶的原理:
MR中:key.hashCode % reductTask
Hive中:分桶字段.hashCode % 分桶个数
创建分桶表
数据
1 | 1 java 90 |
建表
1 | -- 创建分桶表 |
备注:
分桶规则:
分桶字段.hashCode % 分桶数
分桶表加载数据时,使用 insert… select … 方式进行
网上有资料说要使用分区表需要设置 hive.enforce.bucketing=true,那是Hive 1.x 以前的版本;Hive 2.x 中,删除
了该参数,始终可以分桶;
修改表 & 删除
1 | -- 修改表名 rename |
HQL DDL命令小结
- 主要对象:数据库、表
- 表的分类:
- 内部表。删除表时,同时删除元数据和表数据
- 外部表。删除表时,仅删除元数据,保留表中数据;生产环境多使用外部表
- 分区表。按照分区字段将表中的数据放置在不同的目录中,提高SQL查询的性能
- 分桶表。按照分桶字段,将表中数据分开。 分桶字段.hashCode % 分桶数据
- 主要命令:create、alter 、drop
数据导入导出
数据导入
加载数据(LOAD)
1 | LOAD DATA [LOCAL] INPATH 'filepath' [OVERWRITE] INTO TABLE tablename [PARTITION |
- LOCAL:
- LOAD DATA LOCAL … 从本地文件系统加载数据到Hive表中。本地文件会拷贝到Hive表指定的位置
- LOAD DATA … 从HDFS加载数据到Hive表中。HDFS文件移动到Hive表指定的位置
- INPATH:加载数据的路径
- OVERWRITE:覆盖表中已有数据;否则表示追加数据
- PARTITION:将数据加载到指定的分区
示例:
1 | -- 创建表 |
插入数据(INSERT)
1 | -- 创建分区表 |
创建表并插入数据(as select)
1 | -- 根据查询结果创建表 |
使用import导入数据
1 | import table student2 partition(month='201709') from '/user/hive/warehouse/export/student'; |
数据导出
1 | -- 将查询结果导出到本地 |
小结
数据导入:load data / insert / create table …. as select ….. / import table
数据导出:insert overwrite … diretory … / hdfs dfs -get / hive -e “select …” > a.log / export table …
Hive的数据导入与导出还可以使用其他工具:Sqoop、DataX等;
DQL
Data Query Language 数据查询语言
1 | SELECT [ALL | DISTINCT] select_expr, select_expr, ... |
SQL语句书写注意事项:
- SQL语句对大小写不敏感
- SQL语句可以写一行(简单SQL)也可以写多行(复杂SQL)
- 关键字不能缩写,也不能分行
- 各子句一般要分行
- 使用缩进格式,提高SQL语句的可读性(重要)
示例
创建表
1 | -- 测试数据 /home/hadoop/data/emp.dat |
基本查询
1 | -- 省略from子句的查询 |
where子句
比较运算符
比较运算符 | 描述 |
---|---|
=、==、 <=> | 等于 |
<>、!= | 不等于 |
<、<=、 >、>= | 大于等于、小于等于 |
is [not] null | 如果A等于NULL,则返回TRUE,反之返回FALSE。使用NOT关键字结果相反。 |
in (value1, value2, … …) | 匹配列表中的值 |
LIKE | 简单正则表达式,也称通配符模式。 ‘x%’ 表示必须以字母 ‘x’ 开 头; ‘%x’表示必须以字母’x’结尾; ‘%x%’表示包含有字母’x’,可以 位于字符串任意位置。 使用NOT关键字结果相反。 % 代表匹配零个或多个字符(任意个字符); _ 代表匹配一个字符。 |
[NOT] BETWEEN … AND … | 范围的判断,使用NOT关键字结果相反。 |
RLIKE、 REGEXP | 基于java的正则表达式,匹配返回TRUE,反之返回FALSE。 匹配使用的是JDK中的正则表达式接口实现的,因为正则也依据其中的规则。 例如,正则表达式必须和整个字符串A相匹配,而不是只需与其字符串匹配。 |
逻辑运算符
and、or、not
1 | -- 比较运算符,null参与运算 |
group by子句
GROUP BY语句通常与聚组函数一起使用,按照一个或多个列对数据进行分组,对每个组进行聚合操作。
1 | -- 计算emp表每个部门的平均工资 |
where与having
- where子句针对表中的数据发挥作用;having针对查询结果(聚组以后的结果) 发挥作用
- where子句不能有分组函数;having子句可以有分组函数
- having只用于group by分组统计之后
1 | -- 求每个部门的平均薪水大于2000的部门 |
表连接
Hive支持通常的SQL JOIN语句。默认情况下,仅支持等值连接,不支持非等值连 接。
JOIN 语句中经常会使用表的别名。使用别名可以简化SQL语句的编写,使用表名前缀可以提高SQL的解析效率。
连接查询操作分为两大类:内连接和外连接,而外连接可进一步细分为三种类型:
1 | -- 内连接: [inner] join |
1 | -- 准备数据 |
多表连接
连接 n张表,至少需要 n-1 个连接条件。例如:连接四张表,至少需要三个连接条 件。 多表连接查询,查询老师对应的课程,以及对应的分数,对应的学生:
1 | select * |
Hive总是按照从左到右的顺序执行,Hive会对每对 JOIN 连接对象启动一个 MapReduce 任务。
上面的例子中会首先启动一个 MapReduce job 对表 t 和表 c 进行连接操作;然后再 启动一个 MapReduce job 将第一
个 MapReduce job 的输出和表 s 进行连接操作; 然后再继续直到全部操作;
笛卡尔积
满足以下条件将会产生笛卡尔积:
- 没有连接条件
- 连接条件无效
- 所有表中的所有行互相连接
如果表A、B分别有M、N条数据,其笛卡尔积的结果将有 M*N 条数据;缺省条件下 hive不支持笛卡尔积运算;
1 | set hive.strict.checks.cartesian.product=false; |
排序子句
order by
全局排序
- order by 子句出现在select语句的结尾;
- order by子句对最终的结果进行排序;
- 默认使用升序(ASC);可以使用DESC,跟在字段名之后表示降序;
ORDER BY执行全局排序,只有一个reduce
1 | -- 普通排序 |
sort by
每个MR内部排序
对于大规模数据而言order by效率低;
在很多业务场景,我们并不需要全局有序的数据,此时可以使用sort by;
sort by为每个reduce产生一个排序文件,在reduce内部进行排序,得到局部有序的结果;
1 | -- 设置reduce个数 |
distribute by
分区排序
distribute by 将特定的行发送到特定的reducer中,便于后继的聚合 与 排序操作;
distribute by 类似于MR中的分区操作,可以结合sort by操作,使分区数据有序;
distribute by 要写在sort by之前;
1 | -- 启动2个reducer task;先按 deptno 分区,在分区内按 sal+comm 排序 |
cluster by
当distribute by 与 sort by是同一个字段时,可使用cluster by简化语法;
cluster by 只能是升序,不能指定排序规则;
1 | -- 语法上是等价的 |
排序小结
- order by。执行全局排序,效率低。生产环境中慎用
- sort by。使数据局部有序(在reduce内部有序)
- distribute by。按照指定的条件将数据分组,常与sort by联用,使数据局部有序
- cluster by。当distribute by 与 sort by是同一个字段时,可使用cluster by简化 语法
函数
系统内置函数
查看系统函数
1 | -- 查看系统自带函数 |
日期函数
1 | -- 当前前日期 |
字符串函数
1 | -- 转小写。lower |
数学函数
1 | -- 四舍五入。round |
条件函数
1 | -- if (boolean testCondition, T valueTrue, T valueFalseOrNull) |
UDTF函数
UDTF : User Defined Table-Generating Functions。用户定义表生成函数,一行输 入,多行输出。
1 | -- explode,炸裂函数 |
UDTF 案例1
1 | -- 数据(id tags): |
UDTF 案例2
1 | -- 数据准备 |
小结
- 将一行数据转换成多行数据,可以用于array和map类型的数据;
- lateral view 与 explode 联用,解决 UDTF 不能添加额外列的问题
窗口函数
窗口函数又名开窗函数,属于分析函数的一种。
用于解决复杂报表统计需求的功能强 大的函数,很多场景都需要用到。窗口函数用于计算基于组的某种聚合值,它和聚合函数的不同之处是:对于每个组返回多行,而聚合函数对于每个组只返回一行。 窗口函数指定了分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化。
over
关键字over,使用窗口函数之前一般要要通过over()进行开窗
1 | -- 查询emp表工资总和 |
注意:窗口函数是针对每一行数据的;如果over中没有参数,默认的是全部结果集;
partition by
在over窗口中进行分区,对某一列进行分区统计,窗口的大小就是分区的大小
1 | -- 查询员工姓名、薪水、部门薪水总和 |
order by
order by 子句对输入的数据进行排序
1 | -- 增加了order by子句;sum:从分组的第一行到当前行求和 |
Window子句
1 | rows between ... and ... |
如果要对窗口的结果做更细粒度的划分,使用window子句,有如下的几个选项:
- unbounded preceding。组内第一行数据
- n preceding。组内当前行的前n行数据
- current row。当前行数据
- n following。组内当前行的后n行数据
- unbounded following。组内最后一行数据
1 | -- rows between ... and ... 子句 |
排名函数
都是从1开始,生成数据项在分组中的排名。
- row_number()。排名顺序增加不会重复;如1、2、3、4、… …
- RANK()。 排名相等会在名次中留下空位;如1、2、2、4、5、… …
- DENSE_RANK()。 排名相等会在名次中不会留下空位 ;如1、2、2、3、4、… …
1 | -- row_number / rank / dense_rank |
序列函数
- lag。返回当前数据行的上一行数据
- lead。返回当前数据行的下一行数据
- first_value。取分组内排序后,截止到当前行,第一个值
- last_value。分组内排序后,截止到当前行,最后一个值
- ntile。将分组的数据按照顺序切分成n片,返回当前切片值
1 | -- 测试数据 userpv.dat。cid ctime pv |
SQL面试题
连续7天登录的用户
1 | -- 数据。uid dt status(1 正常登录,0 异常) |
每班前三名
分数一样并列,并求差值
1 | -- 数据。sid class score |
行 <=> 列
列=>行
1 | -- 数据:id course |
行=>列
1 | -- 数据。id1 id2 flag |
自定义函数
当 Hive 提供的内置函数无法满足实际的业务处理需要时,可以考虑使用用户自定义 函数进行扩展。用户自定义函数分为以下三类:
- UDF(User Defined Function)。用户自定义函数,一进一出
- UDAF(User Defined Aggregation Function)。用户自定义聚集函数,多进一 出;类似于:count/max/min
- UDTF(User Defined Table-Generating Functions)。用户自定义表生成函 数,一进多出;类似于:explode
UDF开发
- 继承org.apache.hadoop.hive.ql.exec.UDF
- 需要实现evaluate函数;evaluate函数支持重载
- UDF必须要有返回类型,可以返回null,但是返回类型不能为void
UDF开发步骤:
- 创建maven java 工程,添加依赖
- 开发java类继承UDF,实现evaluate 方法
- 将项目打包上传服务器 添加开发的jar包
- 设置函数与自定义函数关联
- 使用自定义函数
扩展系统 nvl 函数功能
1 | -- 系统内建的 nvl 函数 |
将项目打包上传服务器
临时使用
添加开发的jar包(在Hive命令行中)
1
add jar /home/hadoop/hiveudf.jar;
创建临时函数。指定类名一定要完整的路径,即包名加类名
1
create temporary function mynvl as "cn.lagou.hive.udf.nvl";
永久使用
将jar上传HDFS
1
hdfs dfs -put hiveudf.jar jar/
在Hive命令行中创建永久函数
1
create function mynvl1 as 'cn.lagou.hive.udf.nvl' using jar 'hdfs:/user/hadoop/jar/hiveudf.jar';
查询所有的函数,发现 mynvl1 在列表中
1
show functions;
DML
数据操纵语言DML(Data Manipulation Language),DML主要有三种形式:插入 (INSERT)、删除(DELETE)、更新(UPDATE)。
事务(transaction)是一组单元化操作,这些操作要么都执行,要么都不执行,是一个 不可分割的工作单元。
事务具有的四个要素:原子性(Atomicity)、一致性(Consistency)、隔离性 (Isolation)、持久性(Durability),这四个基本要素通常称为ACID特性。
原子性。一个事务是一个不可再分割的工作单位,事务中的所有操作要么都发 生,要么都不发生。
一致性。事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性, 一个事务在执行之前和执行之后,数据库都必须处于一致性状态。
隔离性。在并发环境中,并发的事务是相互隔离的,一个事务的执行不能被其他 事务干扰。即不同的事务并发操纵相同的数据时,每个事务都有各自完整的数据 空间,即一个事务内部的操作及使用的数据对其他并发事务是隔离的,并发执行 的各个事务之间不能互相干扰。
持久性。事务一旦提交,它对数据库中数据的改变就应该是永久性的。
Hive 事务
Hive从0.14版本开始支持事务 和 行级更新,但缺省是不支持的,需要一些附加的配 置。要想支持行级insert、update、delete,需要配置Hive支持事务。
Hive事务的限制:
- Hive提供行级别的ACID语义
- BEGIN、COMMIT、ROLLBACK 暂时不支持,所有操作自动提交
- 目前只支持 ORC 的文件格式
- 默认事务是关闭的,需要设置开启
- 要是使用事务特性,表必须是分桶的
- 只能使用内部表
- 如果一个表用于ACID写入(INSERT、UPDATE、DELETE),必须在表中设置表属性 : “transactional=true”
- 必须使用事务管理器 org.apache.hadoop.hive.ql.lockmgr.DbTxnManager
- 目前支持快照级别的隔离。就是当一次数据查询时,会提供一个数据一致性的快照
- LOAD DATA语句目前在事务表中暂时不支持
HDFS是不支持文件的修改;并且当有数据追加到文件,HDFS不对读数据的用户提供 一致性的。为了在HDFS上支
持数据的更新:
- 表和分区的数据都被存在基本文件中(base files)
- 新的记录和更新,删除都存在增量文件中(delta files)
- 一个事务操作创建一系列的增量文件
- 在读取的时候,将基础文件和修改,删除合并,最后返回给查询
Hive 事务操作示例
1 | -- 这些参数也可以设置在hive-site.xml中 |