Hive面试题

5 篇文章 1 订阅

1、Hive的架构是什么?

在这里插入图片描述

  1. 用户接口:Client

    CLI(command-line interface)、JDBC/ODBC(jdbc访问hive)、WEBUI(浏览器访问hive)

  2. 元数据:Metastore

    元数据包括:表名、表所属的数据库(默认是default)、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等

    默认存储在自带的derby数据库中,推荐使用MySQL存储Metastore

  3. Hadoop

    使用HDFS进行存储,使用MapReduce进行计算

  4. 驱动器:Driver

    • 解析器(SQL Parser):将SQL字符串转换成抽象语法树AST,这一步一般都是用第三方工具完成(antlr);对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误
    • 编译器(Physical Plan):将AST编译生成逻辑执行计划
    • 优化器(Query Optimizer):对逻辑执行计划进行优化
    • 执行器(Execution):把逻辑执行计划转换成可以运行的物理计划,对于Hive来说就是MR

在这里插入图片描述

Hive通过给用户提供的一系列交互接口,接收到用户的指令(SQL),使用自己的Driver,结合元数据(Metastore),将这些指令翻译成MapReduce,提交到Hadoop中执行,最后将执行返回的结果输出到用户交互接口

2、Hive和数据库比较

Hive和数据库除了拥有类似的查询语言,再无类似之处

Hive数据库
数据存储位置存储在HDFS将数据保存在块设备或者本地文件系统中
数据更新不建议对数据改写通常是需要经常进行修改
执行延迟高(数据规模大到超过数据库的处理能力时,Hive的并行计算能体现出优势)低(条件是数据规模小)
数据规模支持很大规模的数据计算可以支持的数据规模较小

3、内部表和外部表

元数据、原始数据

  1. 删除数据时:

    内部表:元数据、原始数据,全删除

    外部表:只删除,元数据

  2. 在公司生产环境下,什么时候创建内部表,什么时候创建外部表?

    在公司中绝大多数场景都是外部表
    自己使用的临时表,才会创建内部表
    

4、分区和分桶的区别?

5、Order By,Sort by,Distrbute By,Cluster By的区别?

Order By:全局排序,只有一个Reducer

Sort By:分区内有序

Distrbute By:类似MR中Partition,进行分区,结合sort by使用

Cluster By:当Distribute by和sort by字段相同时,可以使用cluster by方式;cluster by除了具有distribute by的功能外还兼具sort by的功能,但是排序智能是升序排序,不能制定排序规则为asc或desc

在生产环境中order by用的比较少,容易导致OOM

在生产环境中sort by + distribute by用的多

6、写出你常用的10个Hive内置函数?

  1. date_add、date_sub函数(加减日期)

  2. next_day函数(周指标相关)

  3. date_format函数(根据格式整理日期)

  4. last_day函数(求当月最后一天日期)

  5. collect_set函数

  6. get_json_object解析json函数

  7. NVL(表达式1,表达式2)

    如果表达式1为空值,NVL返回值为表达式2的值,否则返回表达式1的值

7、如何自定义UDF、UDTF函数的?

在项目中是否自定义过UDF、UDTF函数,以及用它们处理了什么问题,及自定义步骤?

用UDF函数解析公共字段;用UDTF函数解析事件字段

自定义UDF:集成UDF,重写evaluate方法

自定义UDTF:继承自GenericUDTF,重写3个方法:initialize(自定义输出的列名和类型),process(将结果返回forward(result)),close

为什么要自定义UDF/UDTF?

因为自定义函数,可以自己埋点Log打印日志,出错或者数据异常,方便调试

8、有哪些窗口函数?

Rank
  1. RANK():排序相同时会重复,总数不会变
  2. DENSE_RANK():排序相同时会重复,总数会减少
  3. ROW_NUMBER():会根据顺序计算
OVER():指定分析函数工作的数据窗口大小,这个数据窗口大小可能会随着行的变化而变化
  1. CURRENT ROW:当前行
  2. n PRECEDING:往前n行数据
  3. n FOLLOWING:往后n行数据
  4. UNBOUNDED:起点,UNBOUNDED PRECEDING表示从前面的起点,UNBOUNDED FOLLOWING表示到后面的终点
  5. LAG(col,n):往前第n行数据
  6. LEAD(col,n):往后第n行数据
  7. NTILE(n):把有序分区中的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号;注意:n必须为int类型

9、Hive有哪些常用的优化手段?

  1. MapJoin

    如果不指定MapJoin或者不符合MapJoin的条件,那么Hive解析器会将Join操作转换成Common Join,即:在Reduce阶段完成join

    容易发生数据倾斜

    可以用MapJoin把小表全部加载到内存在map端进行join,避免reducer处理

    默认是打开的,不要关闭

  2. 行列过滤

    列处理:在SELECT中,只拿需要的列,如果有,尽量使用分区过滤,少用select *

    行处理:在分区裁剪中,当使用外关联时,如果将副表的过滤条件写在where后面,那么就会先全表关联,之后再过滤

  3. 列式存储

  4. 采用分区技术

  5. 合理设置Map数

    mapred.min.split.size:指的是数据的最小分割单元大小,min的默认值是1B

    mapred.max.split.size:指的是数据的最大分割单元大小,max的默认值是256MB

    通过调整max可以起到调整map数的作用,减小max可以增加map数,增大max可以减少map数

    max(0,min(块大小,Long的最大值))

    需要提醒的是,直接调整mapred.map.tasks这个参数是没有效果的

    如果设置org.apache.hadoop.hive.ql.io.HiveInputFormat,上述参数是有效果的

  6. 合理设置Reduce数

    Reduce个数并不是越多越好

    过多的启动和初始化Reduce也会消耗时间和资源

    有多少个Reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题

    在设置Reduce个数的时候也需要考虑这两个原则:处理大数据量利用合适的Reduce数;使单个Reduce任务处理数据量大小要合适

  7. 解决小文件

    小文件如何产生的?

    1、动态分区插入数据,产生大量的小文件,从而导致map数量剧增
    2、reduce数量越多,小文件也越多(reduce的个数和输出文件是对应的)
    3、数据源本省就包含大量的小文件
    

    小文件解决方案?

    1、在Map执行前合并小文件,减少Map数:CombineHiveInputFormat具有对小文件进行合并的功能(系统默认的格式)
    # HiveInputFormat没有对小文件合并功能
    set hive.input.format=org.apache.hadoop.hive.al.io.CombineHiveInputFormat
    
    2、merge:输出合并小文件
    # 默认true,在map-only任务结束时合并小文件
    SET hive.merge.mapfiles = true;
    # 默认false,在map-reduce任务结束时合并小文件
    SET hive.merge.mapredfiles = true;
    # 默认256M
    SET hive.merge.size.per.task = 268435456;
    # 当输出文件的平均大小小于16m该值时,启动一个独立的map-reduce任务进行文件merge
    SET hive.merge.smallfiles.avgsize = 16777216;
    
    3、开启JVM重用
    JVM重用是Hadoop调优参数的内容,其对Hive的性能具有非常大的影响
    特别是对于很难避免小文件的场景或task特别多的场景,这类场景大多数执行时间都很短
    Hadoop的默认配置通常是使用派生JVM来执行map和Reduce任务的
    这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成百上千task任务的情况
    JVM重用可以使得JVM实例在同一个job中重新使用N次
    N的值可以在Hadoop的mapred-site.xml文件中进行配置
    通常在10-20之间,具体多少需要根据具体业务场景测试得出
    # 默认值是1
    <property>
    	<name>mapreduce.job.jvm.numtasks</name>
    	<value>10</value>
    	<description>How many tasks to run per jvm. If set to -1, there is no limit.</description>
    </property>
    这个功能的缺点是,开启JVM重用将一直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放
    如果某个“不平衡的”job中有某几个reduce task执行的时间要比其他Reduce task消耗的时间多的多的话,那么保留的插槽就会一直空闲着却无法被其他的job使用,直到所有的task都结束了才会释放
    set mapreduce.job.jvm.numtasks = 10
    
  8. 开启map端combiner(不影响最终业务逻辑)

    set hive.map.aggr=true;
    
  9. 压缩(选择快的)

    设置map端输出、中间结果压缩(不完全是解决数据倾斜的问题,但是减少了IO读写和网络传输,能提高很多效率)

    # 启用中间数据压缩
    set hive.exec.compress.intermediate=true;
    # 启用最终数据压缩
    set mapreduce.map.output.compress=true;
    # 设置压缩方式  snappy...
    set mapreduce.map.outout.compress.codec=snappy;
    
  10. 采用TEZ引擎或者Spark引擎(Hive有哪些执行引擎,各有哪些区别?

    TEZSpark都是基于内存,速度比MR都要快,MR更稳定

    1. 数据量特别大,不在乎时间,MR引擎更合理,清洗很多用MR引擎
    2. 数据量不大,需要很快出结果,简单计算,用TEZ引擎,临时的需求
    3. 数据比较大,对时效有一定要求,报表,Spark引擎

10、Hive如何解决数据倾斜?

1. 怎么产生的数据倾斜?
  1. 不同数据类型关联产生数据倾斜

    情形:比如用户表中user_id字段为int,long表中user_id字段既有string类型也有int类型,当按照user_id进行两个表的join操作时

    后果:处理此特殊值的reduce耗时,只有一个reduce任务;默认的Hash操作会按int型的id来进行分配,这样会导致所有string类型id的记录都分配到一个Reducer中

    解决方法:把数字类型转换成字符串类型

    select * from users a
    left outer join logs b
    on a.usr_id = cast(b.user_id as string)
    
  2. 控制控制分布

    情形:在生产环境经常会用大量空值数据进入到一个reduce中去,导致数据倾斜

    解决方法:自定义分区,将为空的key转变为字符串加随机数或纯随机数,将因空值而造成倾斜的数据分到多个reducer

    注意:对于异常值如果不需要的话,最好是提前在where条件里过滤掉,这样可以使计算量大大减少

最常见的数据倾斜的场景是key分布不均,个别的key特别多,其他key比较少

2. 解决数据倾斜的方法?
  1. Group By

    如果需要做过滤distinct,假设可以用group by能够实现一样的效果,用group by

    :group by优于distinct group

    解决方法:采用sum() group by()的方式来替换count(distinct)完成计算

  2. MapJoin

    没有shuffle,没有倾斜

  3. 开启数据倾斜时负载均衡

    set hive.groupby.skewindata=true;
    

    思想:就是先随机分发并处理,再按照key group by来分发处理

    操作:当选项设定为true,生成的查询计划会有两个MRJob

    第一个MRJob中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的GroupBy Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的

    第二个MRJob再根据预处理的数据结果按照GroupBy Key分布到Reduce中(这个过程可以保证相同的原始GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作

    点评:它使计算变成了两个mapreduce,先在第一个中在shuffle过程partition时随机给 key打标记,使每个key随机均匀分布到各个reduce上计算,但是这样只能完成部分计算,因为相同key没有分配到相同reduce上

    所以需要第二次的mapreduce,这次就回归正常shuffle,但是数据分布不均匀的问题在第一次mapreduce已经有了很大的改善,因此基本解决数据倾斜,因为大量计算已经在第一次mr中随机分布到各个节点完成

11、Hive里边字段的分隔符用的什么?为什么用\t?有遇到过字段里边有\t的情况吗,怎么处理的?

Hive默认的字段分隔符为ASCII码的控制符\001(^A),建表的时候用fields terminated by '\001'

注意:如果采用\t或者\001为分隔符,需要要求前端埋点和JavaEE后台传递过来的数据不能出现该分隔符,通过代码规范约束

一旦传输过来的数据含有分隔符,需要在前一级数据中转义或者替换(ETL)

12、Tez引擎优点?(Hive有哪些执行引擎,各有哪些区别?

Tez可以将多个有依赖的作业转换为一个作业,这样只需写一次HDFS,且中间节点较少,从而大大提升作业的计算性能

MR/Tez/Spark区别

MR引擎:多job串联,基于磁盘,落盘的地方比较多;虽然慢,但一定能跑出结果;一般处理周、月、年指标

Tez引擎:完全基于内存;注意:如果数据量特别大,慎重使用,容易OOM;一般用于快速出结果,数据量比较小的场景

Spark引擎:虽然在Shuffle过程中也落盘,但是并不是所有算子都需要Shuffle,尤其是多算子过程,中间过程不落盘DAG有向无环图, 兼顾了可靠性和效率,一般处理天指标

13、Hive的sql是如何转化为MapReduce?

了解了MapReduce实现SQL基本操作之后,我们来看看Hive是如何将SQL转化为MapReduce任务的,整个编译过程分为六个阶段:

  1. Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树AST Tree (做语法解析,语法检查,转化为AST Tree)

  2. 遍历AST Tree,抽象出查询的基本组成单元QueryBlock

  3. 遍历QueryBlock,翻译为执行操作树OperatorTree

  4. 逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量,把逻辑计划进行优化,得到优化后的逻辑计划

  5. 遍历OperatorTree,翻译为MapReduce任务,得到物理计划
    后,我们来看看Hive是如何将SQL转化为MapReduce任务的,整个编译过程分为六个阶段:

  6. Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树AST Tree (做语法解析,语法检查,转化为AST Tree)

  7. 遍历AST Tree,抽象出查询的基本组成单元QueryBlock

  8. 遍历QueryBlock,翻译为执行操作树OperatorTree

  9. 逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量,把逻辑计划进行优化,得到优化后的逻辑计划

  10. 遍历OperatorTree,翻译为MapReduce任务,得到物理计划

  11. 物理层优化器进行MapReduce任务的变换,生成最终的执行计划

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值