Hive¶
简述hive¶
我理解的,hive 就是一款构建数据仓库的工具,它可以将结构化的数据映射为一张表,并且可以通过 SQL语句进行查询分析。本质上是将SQL转换为MapReduce 或者spark来进行计算,数据是存储在 hdfs上,简单理解来说 hive就是 MapReduce的一个客户端工具。
你可以说一下 HQL转换为 MR的任务流程吗?¶
首先客户端提交 HOL 以后,hive通过解析器将 SOL转换成抽象语法树,然后通过编译器生成逻辑执行计划,再通过优化器进行优化,最后通过执行器转换为可以运行的物理计划,比如MapReduce/spark,然后提交到yarn 上执行。 详细来说: 1. 首先客户端提交 HQL 以后,Hive 利用 Antlr 框架对 HQL 完成词法语法解析,将 HQL 转换成抽象语法树 2. 然后遍历AST,将其转换成queryblock查询块,可以理解为最小的查询执行单元,比如 where 3. 然后遍历查询块,将其转换为操作树,也就是逻辑执行计划然后使用优化器对操作树进行逻辑优化,源码中会遍历所有的优化方式,比如 mapjoin,谓词下推等,来达到减少 MapReduce Job,减少shuffle 数据量的目的 4. 最后通过执行器将逻辑执行计划转换为物理执行计划(MR到这就结束了)(Tez和Spark还需要使用物理优化器对任务树进行物理优化),提交到hadoop集群运行
你可以说一下hive的元数据保存在哪里吗?¶
默认是保存在 java 自带的 derby数据库,但是这有一个缺点:derby 数据库不支持并发,也就是说不能同时两个客户端去操作derby数据库,因此通常情况下,都会配置一个mysql去存放元数据
hive 和传统数据库之间的区别¶
我认为主要有三点的区别:
- 数据量,hive 支持大规模的数据计算,mysql支持的小一些数据更新快不快,hive 官方是不建议对数据进行修改的,因为非常的慢.这一点我也测试过,而mysql经常会进行数据修改,速度也挺快的
- hive 大多数延迟都比较高的,mysql会低一些,当然这也与数据规模有关,数据规模很大的时候,hive不一定比mysql慢
- 为什么处理小表延迟比较高:因为hive 计算是通过 MapReduce,而MapReduce 是批处理,高延迟的。Hive的优势在于处理大数据,对于处理小数据是没有优势的
hive 的内部表和外部表的区别¶
从建表语句来看,加上了external关键字修饰的就是外部表,没加的就是内部表
我认为主要有两点的区别:
内部表的数据由 hive 自身管理,外部表的数据由hdfs管理 删除内部表的时候,元数据和原始数据都会被删除,而删除外部表的时候仅仅会删除元数据,原始数据不会被删除 使用场景:通常都会建外部表,因为一个表通常要多个人使用,以免删除了,还可以找到数据,保证了数据安全
hive 的 join 底层实现¶
首先 hive 的 join 分为 common join 和 map join,common join 就是 join 发生 在 reduce 端,map join 就是 join 发生在 map 端
common join:
分为三个阶段:map阶段,shutle阶段,reduce阶段
map阶段:对来自不同表的数据打标签,然后用连接字段作为key,其余部分和标签作为value,最后进行输出 shuffle 阶段:根据key的值进行hash,这样就可以将key 相同的送入一个reduce中 reduce 阶段:对来自不同表的数据进行join 操作就可以了
map join:
首先它是有一个适用前提的,适用于小表和大表的join 操作 小表多小为小呢?所以就有了一个参数进行配置:hive.mapjoin.smalltable.filesize-25M 它的原理是将小表复制多份,让每个maptask内存中存在一份,比如我可以存放到 HashMap 中,然后join 的时候,扫描大表,对于大表中的每条记录 key/value,在HashMap中查找是否有相同的key的记录,如果有,则 join 连接后输出即可,因为这里不涉及reduce 操作。 0.7 版本之后,都会自动转换为 mapjoin,如果之前的版本,我们配置个参数就可以了:hive.auto.convert.join=true
Order By 和 Sort By 的区别¶
distribute by:将数据根据by的字段散列到不同的reduce中cluster by:当 distribute by 和 sort by 字段相同的时候,就等价于 cluster by,但是排序只能是升序 order by: 全局排序,只有一个reducer,缺点:当数据规模大的时候,就会需要很长的计算时间 sort by:分区排序,保证每个reducer内有序,一般结合distribute by来使用使用场景:在生产环境中,orderby用的比较少,容易导致OOM;一般使用distribute by+sort by
行转列和列转行函数¶
JSON 解析函数:
- get json object:每次只能返回 json 对象中的一列值 selectget json object(data,'$.movie") as movie from json;
2.json tuple:每次可以返回多列的值 select b.b movie,b.b rate,b.b timeStamp, b.b uidfrom json lateral view json tuple(json.data,'movie','rate",'timeStamp','uid') b as b movie.b rate,b timeStamp, b uid;
如果是json 数组的话,那么就不能直接使用上述的操作,我们可以先使用regexp_replace方法进行字符串的替换,将它处理成多个ison,然后再使用上述的方法就可以了URL解析函数:HOSTOUERY
1.parse url:一对
2.parse url tuple:一对多
常见的行转列包括:一般的聚合函数,比如max,min,sum;还有汇总函数比如 collect list, collect set
常见的列转行就是:explode函数(jsontuple函数),只能传入array或者map 的数据,将它拆分成多行,一般会和1ateral view 一起使用
SELECT movie, category name FROM movie info lateral VIEWexplode(split(category,",")) movie info tmp AS category _name
窗口函数:
Rank:
rank():排序相同的时候,排名会重复,总数不变
dense rankO):排序相同的时候,排名会重复,总数减少row number():排序相同的时候,排名不会重复,总数不变lag(col,n,default):返回往上移n行的数据,不存在则返回 defaultlead(col,n,default):返回往下移n行的数据,不存在则返回 defaultfirst value(col):取分组内排序后,第一个值
last value(col):取分组内排序后,最后一个值
over 用法:首先通过over来指定窗口的特性,比如可以传入partitionby(分组),orderby(排序),rowsbetween..and..指定窗口的范围
CURRENTROW:当前行
nPRECEDING/FOLLOWING:往前/后行数据UNBOUNDEDPRECEDING/FOLLOWING 表示从前面的起点/到后面的终点
默认是 rows between UNBOUNDED PRECEDING and current row
自定义过UDF、UDTF函数吗¶
1.自定义函数
(1)自定义 UDF:
继承 UDF
重写evaluate方法
自定义 UDTF:
继承 GenericUDTF
重写3个方法:initialize,process,close
2.打成iar包,上传到服务器中
3.执行命令:addjar"路径",目的是将jar 添加到 hive中
4.注册临时函数:createtemporaryfunction 函数名 as"自定义函数全类名"
hive小文件过多怎么解决¶
首先我说一下为什么会产生小文件呢,hive中产生小文件,就是在向表中导入数据的时候,通常来说,我们在生产环境下,一般会使用insert+select的方式导入数据,这样会启动MR 任务,那么reduce有多少个就会输出多少个文件,也就是说insert每执行一次啊,就至少会生成一个文件,有些场景下,数据同步可能每10 分钟就会执行一次,这样就会产生大量的小文件。
然后我再说一下为什么要解决小文件呢,不解决不行吗? 首先对于hdfs来说,不适合存储大量的小文件,文件多了,namenode 需要记录元数据就非常大,就会占用大量的内存,影响hdfs性能 存储;对于hive来说,每个文件会启动一个maptask来处理,这样也会浪费资源计算.
最后我说一下怎么解决,使用hive自带的concatenate命令合并小文件,但是它只支持recfile和 orc 存储格式,也可以在MR过程中合并小文件 - map前 设置inputformat 为combinehiveinputformat:在 map 的时候会把多个 文件作为一个切片输入 - map后,reduce前 map输出的时候合并小文件 hive.merge.mapfiles - reduce后 reduce输出的时候合并小文件 hive.merge.mapredfiles 或者 直接设置少一点的reduce数量 mapreduce.job.reduces 也可以使用hadoop的archive归档方式
Hive 优化¶
建表优化: ◼ 分区表:减少全表扫描,通常查询的时候先基于分区过滤,再查询 ◼ 分桶表:按照join字段进行分桶,join的时候就不会全局join,而是桶 与桶之间进行join ◼ 合适的文件格式:公司中默认采用的是ORC的存储格式,这样可以降低 存储空间,内部有两个索引(行组索引和布隆过滤器索引)的东西,可 以加快查询速度 ◆ 我知道的hive的文件存储格式有textFile,sequenceFile,ORC,Parquet; 其中textFile 为 hive 的默认存储格式,它和sequenceFile一样都是基 于行存储的,ORC和Parquet都是基于列存储的。sequenceFile、ORC 和Parque 文件都是以二进制的方式存储的。 ◼ 合适的压缩格式:减少了IO读写和网络传输的数据量,比如常用的LZO (可切片)和snappy ⚫ 语法优化: ◼ 单表查询优化: ◆ 列裁剪和分区裁剪:如果 select * 或者不指定分区,全列扫描和全 表扫描效率都很低(公司规定了必须指定分区,select *没有明确规 定) ◆ group by 优化: ⚫ 开启map端聚合 ⚫ 开启负载均衡:这样生成的查询计划会有两个 MR Job,一个是 局部聚合(加随机数),另外一个是全局聚合(删随机数) ◆ SQL写成多重模式:有多条SQL重复扫描一张表,那么我们可以写 成 from 表 select... select... ◼ 多表查询优化: CBO优化:选择代价最小的执行计划;自动优化 HQL 中多个 Join 的顺序,并选择合适的 Join 算法 ⚫ set hive.cbo.enable = true(默认开启) ◆ 谓词下推:将 SQL 语句中的 where 谓词逻辑都尽可能提前执行, 减少下游处理的数据量。 ⚫ hive.optimize.ppd = true(默认开启) ◆ MapJoin:将join双方比较小的表直接分发到各个Map进程的内存 中,在Map进程中进行join操作,这样就不用进行Reduce,从而提 高了速度 ⚫ set hive.auto.convert.join=true(默认开启) ⚫ set hive.mapjoin.smalltable.filesize=25000000(默认 25M 以下是小 表) ◆ SMB Join:分桶join,大表转换为很多小表,然后分别进行join,最 后union 到一起 ⚫ job优化: ◼ map优化 ◆ 复杂文件增加map数 ◆ 小文件合并 ◆ map端聚合 ◆ 推测执行 ◼ reduce优化 ◆ 合理设置reduce: ⚫ 为什么reduce的数量不是越多越好? ◼ 过多的启动和初始化 reduce 也会消耗时间和资源; ◼ 另外,有多少个 reduce,就会有多少个输出文件,如果生成 了很多个小文件,那么如果这些小文件作为下一个任务的输 入,则也会出现小文件过多的问题; ◆ 推测执行 ◼ 任务整体优化: ◆ fetch抓取:Hive 中对某些情况的查询可以不必使用 MapReduce 计 算【全局查找、字段查找、limit 查找】 hive.fetch.task.conversion=more ◆ 小数据集启用本地模式 hive.exec.mode.local.auto=true ◆ 多个阶段并行执行 set hive.exec.parallel=true ◆ JVM重用:针对小文件过多的时候使用
Hive的实现逻辑,为什么处理小表延迟比较高¶
因为其计算是通过MapReduce,MapReduce是批处理,高延迟的。小文件也要执行MapReduce。Hive的优势在于处理大数据,对于处理小数据没有优势
如何理解Hive,为什么使用Hive¶
hive就是一款构建数据仓库的工具,它可以将结构化的数据映射为一张表,并且可以通过SQL语句进行查询分析。本质上是将SQL转换为MapReduce或者spark来进行计算,数据是存储在hdfs上,简单理解来说hive就是MapReduce的一个客户端工具。
Hive怎么判断是数据倾斜呢¶
某个reduce task,卡在99%半天不动,任务超时被杀掉 通过时间判断:如果某个reduce的时间比其他reduce时间长的多。 通过任务Counter判断:Counter会记录整个job以及每个task的统计信息,可以看输入记录数和输出字 符数
Hive数据倾斜怎么解决¶
null值过滤,如果大key是无意义的脏数据,直接过滤掉。 Skew-GroupBy 优化 Skew-GroupBy 是 Hive 提供的一个专门用来解决分组聚合导致的数据倾斜问题的方案。 其原理是启动两个 MR 任务,第一个 MR 按照随机数分区,将数据分散发送到Reduce, 并完 成部分聚合,第二个 MR 按照分组字段分区,完成最终聚合。(先分区聚合再最终聚合) 使用 Map Join 多用于大表Join小表 ,Join 操作仅在 Map 端就能完成,没有 Shuffle 操作,没有Reduce 阶 段,自然不会产生 Reduce 端的数据倾斜 使用 SkewJoin 会将一个join sql 分为两个job。给倾斜比较严重的key单独开一个job
你理解的hive是什么框架?¶
hive是一个构建在 Hadoop 上的数据仓库工具 (框架)。 可以将结构化的数据文件映射成一张数据表,并可以使用类sql的方式来对这样的数据文件进行读,写以及管理(包括 元数据)。 这套HIVE SQL 简称 HQL。 hive的执行引擎可以是MR、spark、tez。 Hive的本质是将HQL转换成 MapReduce 任务,完成整个数据的分析查询,减少编写MapReduce的复杂度。
HQL执行很慢,怎么排查?¶
- 确定任务卡住的 stage
- 通过 jobname 确定 stage:一般 Hive 默认的 jobname 名称会带上 stage 阶段
- 确定SQL执行代码
- 结合执行计划,则可以判断出是执行哪段代码导致的卡顿
- 分析原因
- 举例说比如分析出是数据倾斜导致的SQL执行很慢
- 追问:怎么判断是数据倾斜导致的呢
- 解决问题
- 接着上面,这里就回答Hive数据倾斜怎么解决
Hive怎么判断是数据倾斜呢¶
某个reduce task,卡在99%半天不动,任务超时被杀掉
通过时间判断:如果某个reduce的时间比其他reduce时间长的多。
通过任务Counter判断:Counter会记录整个job以及每个task的统计信息,可以看输入记录数和输出字符数
Hive数据倾斜怎么解决¶
- null值过滤,如果大key是无意义的脏数据,直接过滤掉。
- Skew-GroupBy 优化
- Skew-GroupBy 是 Hive 提供的一个专门用来解决分组聚合导致的数据倾斜问题的方案。
- 其原理是启动两个 MR 任务,第一个 MR 按照随机数分区,将数据分散发送到Reduce, 并完成部分聚合,第二个 MR 按照分组字段分区,完成最终聚合。(先分区聚合再最终聚合)
- 使用 Map Join
- 多用于大表Join小表 ,Join 操作仅在 Map 端就能完成,没有 Shuffle 操作,没有Reduce 阶段,自然不会产生 Reduce 端的数据倾斜
- 使用 SkewJoin
- 会将一个join sql 分为两个job。给倾斜比较严重的key单独开一个job
hive和spark的区别¶
本质上来说,
hive 是基于Hadoop的一个构建数据仓库的工具,用来进行数据提取、转化、加载,并且它定义了类SQL语言HQL,允许熟悉SQL的用户查询数据。
Spark 是专为大规模数据处理而设计的快速通用的计算引擎,spark 的主要实现目的就是优化mapreduce 执行
HiveSQL与SparkSQL的区别¶
- 执行引擎
- HiveSQL 的默认执行引擎是mapreduce,可以通过配置更换成spark,即 hive on spark
- SparkSQL 本身属于spark生态群的一部分,基于RDD工作
- 性能
- hiveSQL默认解析成mapreduce任务计算,中间结果需要落盘,以进程的方式运行,性能较差
- sparkSQL将SQL转换成spark的RDD或DataFrame操作,利用内存计算,以线程的方式运行,性能较好
- 优化器
- hiveSQL使用的是基于代价的优化器,即CBO
- sparkSQL会使用Catalyst优化器
hive on spark大体与SparkSQL结构类似,只是SQL解析器不同,但是计算引擎都是spark!
Hive On Spark引擎的特点¶
窗口化函数怎么多行变一行¶
一行变多行: LATERAL VIEW explode (split(col_name,','))
多行变一行:collectset() 去重;collectlist() 不去重
讲讲几个udf的区别¶
- udf:一对一,输入一行输出一行
- udaf:多对一,用户自定义聚合函数
- udtf:一对多,用户自定义生成函数
hive怎样引入 udf 的¶
- (1)pom.xml 增加 hive-exec 依赖
- (2)编写Java ,继承 UDF,实现方法 evaluate
- (3)打包上传服务器lib下,并赋权
- (4)进入hive 通过add jar 命令导入jar包
- (5)创建临时函数指定jar包
- (6)运行自定义UDF
hive遇到过慢查询吗?如何解决(排查)?¶
- 确定任务卡住的 stage
- 通过 jobname 确定 stage:一般 Hive 默认的 jobname 名称会带上 stage 阶段,webUI上面可以直接看
- 确定SQL执行代码
- 结合执行计划,则可以判断出是执行哪段代码导致的卡顿
- 分析原因
- 举例说比如分析出是数据倾斜导致的SQL执行很慢
- 追问:怎么判断是数据倾斜导致的呢
- 某个reduce的时间比其他reduce时间长的多。
- 解决问题
- 接着上面,这里就回答Hive数据倾斜怎么解决
- 如果大key无意义,直接过滤
- Skew-GroupBy 优化,原理是启动两个MR任务先分区聚合再最终聚合
- 使用 Map Join,大表join小表,减少shuffle操作
- 使用 Skew Join,给倾斜比较严重的key单独开一个job
hive的内外部表区别¶
| 对比项 | 内部表 | 外部表 |
|---|---|---|
| Hive 管理范围 | 元数据、实际的表数据 | 元数据 |
| 建表语句 | 不需要 external 关键字修饰 | 需要 external 关键字修饰 |
| drop 删除表后果 | 删除元数据和实际的表数据 | 只删除元数据,实际的表数据保留 |
| 存储路径 | 一般在默认位置存储数据 | 一般搭配 location 指定数据存放位置 |
| 表结构和分区更改的区别 | 自动同步到元数据 | 需要修复表 |
hive json函数¶
两个内置函数
getjsonobject 语法:get_json_object(json_string, '$.column')
json_tuple 语法:json_tuple(json_string, column1, column2, column3 ...)
hive开窗函数¶
开窗函数(Window Function)也叫窗口函数,它可以在当前行所在的窗口范围内进行计算,不会像GROUP BY那样改变行数,而是为每一行输出计算结果,常用于分组排序、累计求和、移动平均等场景。
- 开窗函数基本语法
函数名(列) OVER([PARTITION BY 分组列] [ORDER BY 排序列] [ROWS BETWEEN 起始行 AND 结束行])
- OVER():定义窗口的范围,所有开窗函数都需要这个关键字
- PARTITION BY:按照指定字段对数据进行分区(分组),开窗函数在每个分区内独立计算,不跨分区计算
- ORDER BY:在分区内对数据进行排序,决定计算顺序
-
ROWS BETWEEN:控制窗口的范围,即当前计算要包含哪些行
-
窗口范围说明
| 关键字 | 含义 |
|---|---|
UNBOUNDED PRECEDING |
分区内从第一行开始 |
UNBOUNDED FOLLOWING |
到分区内最后一行结束 |
CURRENT ROW |
从当前行开始/结束 |
n PRECEDING |
当前行往前n行 |
n FOLLOWING |
当前行往后n行 |
常用示例:
- ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW:从第一行到当前行(累计求和常用)
- ROWS BETWEEN 2 PRECEDING AND CURRENT ROW:最近3行(包含当前行),用于移动平均
- ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING:整个分区所有行
默认窗口范围:
- 如果指定了 ORDER BY,默认是 ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
- 如果没有指定 ORDER BY,默认是 ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING
-
开窗函数分类
-
聚合开窗函数 在窗口范围内执行聚合计算:
| 函数 | 说明 |
|---|---|
SUM(col) |
窗口内求和 |
COUNT(col) |
窗口内计数 |
AVG(col) |
窗口内求平均 |
MAX(col) |
窗口内求最大值 |
MIN(col) |
窗口内求最小值 |
示例:求每个部门每个月的累计销售额
SELECT
dept,
month,
sales,
SUM(sales) OVER (PARTITION BY dept ORDER BY month) AS cum_sales
FROM sales_table;
- 排序开窗函数 对分区内数据排序,生成排名:
| 函数 | 相同值排名 | 排名是否跳号 | 总数 | 适用场景 |
|---|---|---|---|---|
row_number() |
不重复,依次递增 | 不跳号 | 不减少 | 取TopN、去重 |
rank() |
相同值同排名 | 跳号 | 不变 | 竞赛排名 |
dense_rank() |
相同值同排名 | 不跳号 | 减少 | 百分等级 |
举例对比(数据:100, 100, 90, 80):
| 分数 | row_number | rank | dense_rank |
|---|---|---|---|
| 100 | 1 | 1 | 1 |
| 100 | 2 | 1 | 1 |
| 90 | 3 | 3 | 2 |
| 80 | 4 | 4 | 3 |
典型应用:每个部门薪资Top3:
SELECT * FROM (
SELECT
dept,
name,
salary,
row_number() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn
FROM employee
) t WHERE rn <= 3;
- 分析开窗函数 用于数据偏移、取值等分析:
| 函数 | 说明 |
|---|---|
LAG(col, n, default) |
获取当前行往前第n行的col值,找不到返回default,常用于计算同比环比 |
LEAD(col, n, default) |
获取当前行往后第n行的col值,找不到返回default |
FIRST_VALUE(col) |
窗口内排序后第一个值 |
LAST_VALUE(col) |
窗口内排序后最后一个值 |
NTILE(n) |
将分区内数据分为n份,返回当前行所在的编号,常用于分组取前百分之几 |
LAG使用示例(计算环比增长率):
SELECT
month,
sales,
LAG(sales, 1) OVER (ORDER BY month) AS last_month_sales,
(sales - LAG(sales, 1) OVER (ORDER BY month)) / LAG(sales, 1) OVER (ORDER BY month) AS rate
FROM sales_table;
NTILE使用示例(取前30%数据):
SELECT * FROM (
SELECT
*,
NTILE(10) OVER (ORDER BY score DESC) AS nt
FROM student
) t WHERE nt <= 3;
-
开窗函数 vs GROUP BY
-
GROUP BY:分组后聚合,行数减少为分组数,每组一行
- 开窗函数:在窗口内计算,行数不变,原表每一行都输出计算结果,更灵活
Hive内部表和外部表的区别?分区和分桶的使用场景?¶
如何用Hive SQL统计近7天每小时的平均请求量?(给出表结构和SQL)¶
你提到用Hive分析数据,如何优化一个执行缓慢的Hive SQL查询?¶
- 参考回答:
- 检查数据倾斜:通过DISTRIBUTE BY对Key重分布;
- 分区裁剪:避免全表扫描,利用分区字段过滤;
- 小文件合并:使用ALTER TABLE CONCATENATE减少Map任务数。