当前位置:   article > 正文

大数据面试题 —— Hive

大数据面试题 —— Hive

Hive 是什么


Hive 是由 Facebook 开源用于解决海量结构化日志的数据统计工具。它是基于 Hadoop 的一个 数据仓库工具,可以将结构化的数据文件映射为一张表,并提供 类 SQL 查询功能。

其本质就是将 HQL 转化成 MapReduce 程序。

  • Hive处理的数据存储在HDFS
  • Hive分析数据底层的实现是MapReduce
  • 执行程序运行在YARN上

为什么要使用 Hive


Hive是Hadoop生态系统中比不可少的一个工具,它提供了一种SQL(结构化查询语言)方言,可以查询存储在Hadoop分布式文件系统(HDFS)中的数据或其他和Hadoop集成的文件系统。

大多数数据仓库应用程序都是使用关系数据库进行实现的,并使用SQL作为查询语言。
Hive是一个构建在Hadoop之上的数据仓库工具,它提供了类似于SQL的查询语言——HiveQL,这使得那些熟悉关系型数据库和SQL的开发人员能够更容易地迁移到Hadoop生态系统上。Hive降低了将这些应用程序转移到Hadoop系统上的难度。凡是会使用SQL语言的开发人员都可以很轻松的学习并使用Hive。

如果没有Hive,那么这些用户就必须学习新的语言和工具,然后才能应用到生产环境中。另外,相比其他工具,Hive更便于开发人员将基于SQL的应用程序转移到Hadoop中。如果没有Hive,那么开发者将面临一个艰巨的挑战,如何将他们的SQL应用程序移植到Hadoop上。

Hive 的优缺点


(1)优点

  • 操作接口采用类 SQL 语法,提供快速开发的能力(简单、容易上手)。
  • 避免了去写 MapReduce,减少开发人员的学习成本。
  • Hive 的执行延迟比较高,因此 Hive 常用于数据分析,对 实时性要求不高 的场合。
  • Hive 的执行延迟比较高,因此其优势在于处理大数据,对于处理小数据没有优势。
  • Hive 支持用户自定义函数,用户可以根据自己的需求来实现自己的函数。

(2)缺点

  • Hive的HQL表达能力有限
    • Hive自动生成的MapReduce作业,通常情况下不够智能化。
    • 数据挖掘方面不擅长,由于MapReduce数据处理流程的限制,效率更高的算法却无法实现。
  • Hive的效率比较低
    • Hive的执行延迟比较高,因此Hive常用于数据分析,对实时性要求不高的场合。
    • Hive调优比较困难,粒度较粗。
  • Hive不支持实时查询和行级别更新
    • Hive分析的数据是存储在HDFS上,HDFS不支持随机写,只支持追加写,所以在Hive中不能update和delete,能select和insert。

Hive的实现逻辑,为什么处理小表延迟比较高


因为其计算是通过MapReduce,MapReduce是批处理,高延迟的。 对于小表查询,MapReduce框架在启动任务、分配资源、执行任务以及回收资源等方面都存在一定的开销,这些开销可能比任务执行的时间还要长,这就会导致处理小表的延迟比较高。

你可以说一下 HQL 转换为 MR 的任务流程吗 ***


在这里插入图片描述

首先客户端提交 HQL 以后,hive 通过 解析器 将 SQL 转换成抽象语法树,然后通过 编译器 生成逻辑执行计划,再通过 优化器 进行优化,最后通过 执行器 转换为可以运行的物理计划,比如 MapReduce/spark,然后提交到 yarn 上执行。

你可以说一下 hive 的元数据保存在哪里吗 ***


默认是保存在 derby 数据库,但是这有一个缺点:derby 数据库不支持并发,也就是说不能同时两个客户端去操作 derby 数据库,因此通常情况下,都会配置 mysql 去存放元数据。

Hive与传统数据库之间的区别


我认为主要有三点的区别:

  • 数据量,hive 支持大规模的数据计算,mysql 支持的小一些。
  • 数据更新快不快,hive 官方是不建议对数据进行修改的,因为非常的慢,这一点我也测试过,而 mysql 经常会进行数据修改,速度也挺快的。
  • 查询快不快,hive 大多数延迟都比较高的,mysql 会低一些,当然这也与数据规模有关,数据规模很大的时候,hive 不一定比 mysql 慢。
  • 应用场景,数据库可以用在 Online 的应用中,但是Hive 是为数据仓库而设计的。

在这里插入图片描述

Hive内部表和外部表的区别 ***


从建表语句来看,未被 external 修饰的是内部表,被 external 修饰的就是外部表。

二者主要有两点区别

  • 内部表的数据由 hive 自身管理,外部表的数据由 hdfs 管理。
  • 删除内部表的时候,元数据和原始数据都会被删除,而删除外部表的时候仅仅会删除元数据,原始数据不会被删除。

使用场景:

  • 内部表适合存储对数据的修改和删除操作,因为删除内部表时可以直接删除相关的数据文件。一般内部表在数仓中的DW(细节层)中使用。
  • 外部表适合存储对数据的只读操作,比如将已经存在的数据文件导入到Hive中进行分析。一般外部表在数仓中的ODS层(贴源层)中使用

外部表相对来说更加安全些,数据组织也更加灵活,方便共享源数据。
在做统计分析时候用到的中间表,结果表可以使用内部表,因为这些数据不需要共享,使用内部表更为合适。

hive 动态分区与静态分区的区别


hive本身是没有索引的,查询数据时需要全表扫描,分区也就是分目录,可以减少全表扫描。

静态分区:

  • 分区字段的值是在导入数据的时候手动指定的

动态分区

  • 分区字段的值是基于查询结果自动推断出来的,也就是最后查询结果的最后一个字段值就对应分区字段的值
  • 想使用动态分区表的时候必须要对 hive 进行两个配置
    • 开启动态分区功能 hive.exec.dynamic.partition=true
    • 设置动态分区的模式为非严格模式,也就是说允许所有分区字段都可以使用动态分区hive.exec.dynamic.partition.mode-nonstrict

分桶表和分区表的区别 ***


分桶表和分区表的作用都是用来减少全表扫描的。因为并非所有的数据都可以进行合理的分区,所以有了新的技术分桶表。分桶表的分桶规则是,根据分桶字段的hash 值,对桶的个数进行取 余运算,然后得到该数据应该放到哪个桶里面去。

(1)创建语句不同,分区表是 partitioned by,分桶表是 clustered by

(2)分区或分桶字段要求不同,分区字段不能是表中存在的字段,分桶字段一定是表中存在的字段。

(3)表现形式不同,分区表是其实就是分了目录存放数据,分桶表是将一个文件拆分为很多文件存放。

hive 的 join 底层实现


(1)Map Join

Map Join的实现方式有两种,分别是Bucket Map Join和Map Join。

  • Bucket Map Join又叫桶映射连接,它是Map Join的一种实现方式,要求表在join列上进行了bucket操作,并且bucket数相同,这样在map端会将两张表中的同一个bucket同时读取进内存中,进行join操作。
  • Map Join是将小表全部缓存到内存中,然后将大表的一条记录与小表在内存中的所有记录进行匹配,匹配成功后输出join结果。
    • Map Join适用于小表驱动大表的情况,它可以极大地减少数据的读取量,加快join的速度。但是它的缺点是要求小表可以全部缓存到内存中。

(2)Reduce Join是指将两张表的数据都读入HDFS,然后在reduce端进行join操作。

Reduce Join分为Shuffle Join和Merge Join两种实现方式。

  • Shuffle Join(又称普通的Reduce Join)是指先对两张表进行分区操作(Partition),然后在reduce阶段进行join操作。
    • Shuffle Join的缺点是,因为需要将两张表的所有数据都拷贝到reduce端,所以在数据量较大的情况下,网络传输的开销很大,执行时间较长。
  • Merge Join又叫排序合并连接,它是Reduce Join的一种实现方式。它首先对需要join的表按照join列进行排序,然后再按照 join 列将两张表join在一起。
    • Merge Join的优点是不需要进行shuffle操作,执行效率较高。但是它的缺点是需要进行排序,如果需要join的表比较大,排序的时间和开销也比较大。

Map Join适用于小表驱动大表的情况,Reduce Join适用于大表驱动小表的情况,不同的实现方式在不同的情况下会有不同的优劣点。

Hive中大表和小表怎么聚合的?复制小表到map task的过程是什么样的?


当进行大表和小表的聚合操作时,Hive会根据优化器的规则自动选择合适的执行计划。一般来说,如果小表可以放在内存中,那么会先将小表复制到每个Map Task的内存中进行处理,然后再将结果传输回Reduce Task进行汇总,这个过程被称为Map Join。

复制小表到map task的过程,这个过程被称为Replication:

  • 在Hive中,如果一个表被标记为小表(Small Table),那么它会被缓存在Hive服务器的本地内存中。
  • 当执行包含小表和大表的Join操作时,Hive会启动MapReduce Job进行处理。
  • 在Map任务执行之前,Hive会将小表从本地内存复制到每个Map任务所在的节点上。
  • 在Map任务执行过程中,每个Map任务都可以直接读取本地节点上的小表数据,而不需要通过网络传输,从而大大加快了处理速度。

注意:只有当小表可以全部放入内存中时,才会使用 Map Join 来加速处理。如果小表的数据量太大,无法全部放入内存中,那么就必须使用普通的Reduce Join来处理,这种情况下,小表会和大表一样被划分为多个分片,分发到不同的Map任务上进行处理,最后再通过Reduce任务进行合并。

大表和大表之间的 join 怎么避免内存溢出?


(1)增加集群资源:通过增加Hadoop集群中的节点数或者增加每个节点的资源,例如内存、CPU等,来提高查询的性能和容错能力。

(2)使用Bucket Map Join:Bucket Map Join是一种将 join 操作划分为多个小任务的技术,可以减少每个任务的数据量,从而降低内存的消耗。在使用Bucket Map Join时,需要将表分桶,且分桶的列应该是 join 条件中的列。(要求表在join列上进行了bucket操作,并且bucket数相同,这样在map端会将两张表中的同一个bucket同时读取进内存中,进行join操作)

(3)使用Map Join:Map Join是一种将小表读入内存中的技术,可以减少内存的消耗。在使用Map Join时,需要将小表进行适当的压缩和优化,以提高查询的性能。

(4)使用索引:在Hive 3.0及以上版本中,可以使用ACID表的索引功能来优化查询,从而降低内存的消耗。通过对大表的索引,可以加速查询的速度,同时减少内存的使用。

Order By 和 Sort By 的区别


Order By:全局排序,只有一个 reducer,缺点: 当数据规模大的时候,就会需要很长的计算时间。

Sort By:分区排序,保证每个 reducer 内有序,一般结合 distribute by 来使用。

使用场景:在生产环境中,order by 用的比较少,容易导致 OOM;一般使用 distribute by+sort by

行转列和列转行函数


(1)行转列:一行转一列、多行转一列

CONCAT(string A/col, string B/col…):返回输入字符串连接后的结果,支持任意多个输入字符串。

CONCAT_WS(separator, str1, str2,…):它是一个特殊形式的 CONCAT()。第一个参数剩余参数间的分隔符。分隔符可以是与剩余参数一样的字符串。如果分隔符是NULL,返回值也将为NULL。这个函数会跳过分隔符参数后的任何NULL和空字符串。分隔符将被加到被连接的字符串之间。

COLLECT_SET(col):函数只接受基本数据类型,它的主要作用是将某字段的值进行去重汇总,产生array类型字段。

COLLECT_LIST(col):函数只接受基本数据类型,它的主要作用是将某字段的值进行不去重汇总,产生arr类型字段。

(2)列转行:

EXPLODE(col):将Hive一列中复杂的 array 或者 map 结构拆分成多行。(如果是array,结果只有一列,如果是map,结果只有key,value两列)

自定义过 UDF函数吗


(1)承UDF或者UDAF或者UDTF,实现特定的方法;

(2)打成jar包,上传到服务器

(3)执行命令 add jar路径,目的是将 jar 包添加到 hive 中

(4)注册临时函数:create temporary function 函数名 as "自定义函数全类名"

(5)在select中使用 UDF 函数

Hive中有很多重复的数据,你如何去重?


(1)使用 DISTINCT关键字

可以在 SELECT 语句中选择不同的值,以去除重复数据。
例如:SELECT DISTINCT column_name FROM table_name;

(2)使用 GROUP BY

可以使用 GROUP BY 子句和聚合函数去掉重复数据。
例如:SELECT column_name, COUNT(*) FROM table_name GROUP BY column_name;

(3)使用窗口函数

可以使用窗口函数来进行去重。

需要注意的是,这种方法可能会影响性能,因为需要进行排序和分组操作,尤其是在处理大数据集时,可能会非常耗时。总的来说,对于数据去重,推荐使用 GROUP BY 的方式,执行效率较高。在需要处理复杂的去重逻辑时,可以考虑使用窗口函数,但需要注意性能问题。

count(distinct)会出现什么问题


我们写的是HQL,而它的底层引擎是MapReduce,是分布式计算的,所以自然会出现数据倾斜这种分布式计算的典型问题,就会导致运行时间过长。这里其实熟悉MapReduce原理的已经明白了这条sql跑的慢的原因,因为出现了很严重的数据倾斜,很多个mapper,却只有1个reducer,所有的数据在mapper处理过后全部只流向了一个reducer。

为什么只有一个reducer呢?因为使用了distinct和count(full aggreates),这两个函数产生的MapReduce作业只会产生一个reducer,而且哪怕显式指定set mapred.reduce.tasks=100000也是没用的。所以对于这种去重统计,如果在数据量够大,一般是一亿记录数以上(根据实际情况考虑),建议选择使用count加group by去进行统计,执行速度就会快很多。

总结:在数据量很大的情况下,使用count+group by替换count(distinct)能使作业执行效率和速度得到很大的提升,一般来说数据量越大提升效果越明显。

hive 小文件过多怎么办


hive 哪里会产生小文件

  • 源数据本身有很多小文件
  • 动态分区会产生大量小文件
  • reduce个数越多,小文件越多
  • 按分区插入数据的时候会产生大量的小文件, 文件个数 = maptask个数 * 分区数
  • mapreduce过程中合并小文件:map后reduce前,map输出的时候设置小文件合并,ruduce输出的时候设置小文件合并。
  • 直接设置少一点的 reduce。 mapreduce.job.reduces
  • hadoop自带的解决小文件的方式:
    • 在计算的时候,采用 CombineTextInputFormat 的切片方式,这样就可以将多个小文件放到一个切片中进行计算
    • Sequence file 由一系列的二进制key/value组成,如果为key小文件名,value为文件内容,则可以将大批小文件合并成一个大文件。
    • 采用 har 归档的方式对小文件进行存储,这样能够将多个小文件打包为一个har 文件

Hive 优化


(1)建表优化

  • 分区表
  • 分桶表
  • 合适的文件格式
  • 合适的压缩格式

(2)语法优化

  • 列裁剪与分区裁剪
  • Group By 优化
    • 开启Map端聚合
    • 开启负载均衡
  • CBO 优化:选择代价最小的执行计划;自动优化 HOL 中多个 Join
    的顺序,并选择合适的 Join 算法。
  • 谓词下推:将 SOL 语句中的 where 谓词逻辑都尽可能提前执行
    减少下游处理的数据量。
  • MapJoin:将Join双方比较小的表直接分发到各个Map进程的内存中,在Map进程中进行Join操作,这样就不用进行Reduce步骤,从而提高了速度。
  • SMB Join:分桶join,大表转换为很多小表,然后分别进行 join,最后 union 到一起。

(3)Job优化

  • Hive Map优化
    • 复杂文件增加Map数
    • 在map执行前合并小文件,减少map数
    • Map端聚合
  • Hive Reduce优化
    • 合理设置Reduce数
    • 为什么 reduce 的数量不是越多越好?
      • 过多的启动和初始化 reduce 也会消耗时间和资源;另外,有多少个 reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题。
  • Hive 任务整体优化
    • 开启Fetch抓取。Hive中对某些情况的查询可以不必使用MapReduce计算。hive.fetch.task.conversion=more
    • 小数据集启用本地模式:hive.exec.mode.local.auto=true
    • 多个阶段并行执行:set hive.exec.parallel-true
    • JVM 重用:针对小文件过多的时候使用

Hive的函数:UDF、UDAF、UDTF的区别


(1)UDF:单行进入,单行输出

(2)UDAF:多行进入,单行输出

(3)UDTF:单行输入,多行输出

所有的Hive任务都会有MapReduce的执行吗


不是,从 Hive 0.10.0 版本开始,对于简单的不需要聚合的类似 SELECT from LIMIT n语句,不需要 MapReduce job,直接通过 Fetch task 获取数据。

Hive的文件存储格式都有哪些


Hive的文件存储格式有四种:TEXTFILE 、SEQUENCEFILE、ORC、PARQUET,前面两种是行式存储,后面两种是列式存储。如果为textfile的文件格式,直接load,不需要走MapReduce;如果是其他的类型就需要走MapReduce了,因为其他的类型都涉及到了文件的压缩,这需要借助MapReduce的压缩方式来实现。

(1)TEXTFILE:按行存储,不支持块压缩,默认格式,数据不做压缩,磁盘开销大,加载数据的速度最高;

(2)ORCFile:存储方式:数据按行分块,每块按照列存储压缩快,快速列存取效率比rcfile高,是rcfile的改良版本,使用了索引使用ORC文件格式可以提高hive读、写和处理数据的能力PARQUET:按列存储,相对于ORC,Parquet压缩比较低,查询效率较低
SequenceFile:Hadoop API提供的一种二进制文件,以<key,value>的形式序列化到文件中存储方式:行存储

总结压缩比:ORC > Parquet > textFile(textfile没有进行压缩)
查询速度:三者几乎一致

你用过哪些窗口函数


窗口函数:就是给聚合函数开操作的窗口(在明细查询中,展示汇总的结果)

rank、dense_rank、row_number

LAG(col,n,default_val):往前第n行数据。

LEAD(col,n, default_val):往后第n行数据。

FIRST_VALUE (col,true/false):当前窗口下的第一个值,第二个参数为true,跳过空值。

LAST_VALUE (col,true/false):当前窗口下的最后一个值,第二个参数为true,跳过空值。

NTILE(n):把有序窗口的行分发到指定数据的组中,各个组有编号,编号从1开始,对于每一行,NTILE返回此行所属的组的编号。

rank、dense_rank、row_number 的区别


在SQL中,ROW_NUMBER()、RANK()和DENSE_RANK()是用于排序的窗口函数,它们在生成排序结果时有一些区别:

  • RANK():排序相同时会重复,总数不变,即会出现1、1、3这样的排序结果;
  • DENSE_RANK():排序相同时会重复,总数会减少,即会出现1、1、2这样的排序结果;
  • ROW_NUMBER()排序相同时不会重复,会根据顺序排序,即会出现1、2、3这样的排序结果;

count(*)、count(列名)、count(1)有什么区别


性能上:count(*)=count(1)>count(主键字段)>count(普通字段)

COUNT DISTINCT 和先 GROUP BY 再 COUNT


COUNT DISTINCT 和先 GROUP BY 再 COUNT 的操作在Hive中都用于去重计数。

COUNT DISTINCT 通常会将所有数据发送到一个Reduce任务进行去重计数,容易导致单一任务的负载过重,尤其是在数据量大且倾斜严重的情况下。

union all 和 union 的区别


union all:对两个结果集直接进行并集操作,记录可能有重复,不会进行排序。

union:对两个结果集进行并集操作,会进行去重,记录不会重复,按字段的默认规则排序。因此,从效率上说,union all 要比union更快。

Hive和spark的区别


即mapreduce与spark的区别

HQL 执行的很慢怎么定位到哪一句


开启慢查询日志,记录了在 mysql 中响应时间超过阈值的语句,这个时间默认是10s。

Hive 数据倾斜


如何解决数据倾斜?

  • 开启map端聚合,相当于Combiner
  • 使用随机数(重新设计key)
  • 设置合理的map、reduce的task数
  • SQL语句调节
    • 大小表Join:使用map join让小的维度表(1000条以下的记录条数)先进内存。在map端完成reduce。
    • 大表Join大表:把空值的key变成一个字符串加上随机数,把倾斜的数据分到不同的reduce上,由于null值关联不上,处理后并不影响最终结果。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/633579
推荐阅读
相关标签
  

闽ICP备14008679号