Hive常见面试题整理(更新中)

1.Hive数据倾斜问题。
数据倾斜:数据倾斜主要表现在,map/reduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),这条Key所在的reduce节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完。

产生原因:1)key分布不均匀
     2)业务数据本身的特性
     3)SQL语句造成数据倾斜

表现:任务进度长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。因为其处理的数据量和其他reduce差异过大,单一reduce的记录数与平均记录数差异过大,通常可能达到3倍甚至更多, 最长时长大于平均时长。

产生数据倾斜的业务场景及解决办法:
1)空值产生的数据倾斜
  在日志中,常会有信息丢失的问题,比如日志中的 user_id,如果取其中的 user_id 和用户表中的 user_id 相关联,就会碰到数据倾斜的问题。
解决方案 1:user_id 为空的不参与关联

select * from log a join user b on a.user_id is not null and a.user_id = b.user_id
  • 1

解决方案 2: 赋予空值新的 key 值

select * from log a left outer join user b on
case when a.user_id is null then concat('hive',rand()) else a.user_id end = b.user_id
  • 1
  • 2

空值的 key 变成一个字符串加上一个随机数,就能把造成数据倾斜的数据分到不同的 reduce 上解决数据倾斜的问题。

2)不同数据类型关联产生数据倾斜
  用户表中 user_id 字段为 int,log 表中 user_id 为既有 string 也有 int 的类型, 当按照两个表的 user_id 进行 join 操作的时候,默认的 hash 操作会按照 int 类型的 id 进行分配,这样就会导致所有的 string 类型的 id 就被分到同一个 reducer 当中。
解决方案:转换为相同数据类型

select * from user a left outer join log b on b.user_id = cast(a.user_id as string)
  • 1

3)大小表关联查询产生数据倾斜
  使用map join让小的维度表(1000条以下的记录条数)先进内存。在map端完成进行join操作。  ---看到
  map join 概念:将其中做连接的小表(全量数据)分发到所有 MapTask 端进行 Join,从而避免了 reduceTask,前提要求是内存足以装下该全量数据
  map join使用限制:必须是join中从表(子查询)数据比较小。所谓从表,即左外连接的右表,或者右外连接的左表。
  map join的适用场景:如关联操作中有一张表非常小,不等值的连接操作。通过上面分析你会发现,并不是所有的场景都适合用MapJoin,它通常会用在如下的一些情景:在两个要连接的表中,有一个很大,有一个很小,这个小表可以存放在内存中而不影响性能。这样我们就把小表文件复制到每一个Map任务的本地,再让Map把文件读到内存中待用。
  在 hive 中,直接提供了能够在 HQL 语句指定该次查询使用 map join.
  首先设置map join:

set hive.auto.convert.join= true;//设置mapjoin
  • 1

  在 hive0.11 版本以后会自动开启 map join 优化,由两个参数控制:

set hive.auto.convert.join=true; //设置 MapJoin 优化自动开启
set hive.mapjoin.smalltable.filesize=25000000 //设置小表不超过多大时开启 mapjoin 优化
  • 1
  • 2

  map join 的用法是在查询/子查询的SELECT关键字后面添加/ * + MAPJOIN(tablelist) * /提示优化器转化为map join。
  详细举例如下:join操作一般都是在reduce阶段完成的,写sql的时候要注意把小表放在join的左边,原因是在 Join 操作的 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生 out of memory 错误的几率。 一个大表和一个配置表的reduce join经常会引起计算不均衡的情况。比如配置表gender_config(gender string,gender_id int)。把“男”“女”字符串映射成一个id。配置表和上面的user表join的sql如下: select user.id , gender_config.gender_id from gender_config join user on gender_config.gender=user.gender。gender 只有男女两个值,hive处理join的时候把join_key作为reduce_key,因此会出现和group by类似的reduce计算不均衡现象,只有两个reduce参与计算,每个reduce计算100亿条记录。
在这里插入图片描述
  这种大表和配置表通常采用map join的方式来解决这种不均衡的现象。目前hive是采用/ * + MAPJOIN(gender_config) * /提示的方式告诉翻译器把sql翻译成mapjoin,提示里必须指明配置表是哪个。 select /*+ MAPJOIN(gender_config) */ user.id , gender_config.gender_id from gender_config join user on gender_config.gender=user.gender
在这里插入图片描述

4)小文件过多:
当出现小文件过多,需要合并小文件。解决方法:set hive.merge.mapfiles=true
1>hive.map.aggr=true:map端部分聚合。

set hive.map.aggr=true //map端部分聚合,相当于Combiner,可以减小压力(默认开启)
  • 1

例: 先看看下面这条SQL:select user.gender,count(1) from user group by user.gende。由于用户的性别只有男和女两个值 (未知)。如果没有map端的部分聚合优化,map直接把groupby_key 当作reduce_key发送给reduce做聚合,就会导致计算不均衡的现象。虽然map有100万个,但是reduce只有两个在做聚合,每个reduce处理100亿条记录。
在这里插入图片描述
没开map端聚合产生的计算不均衡现象
hive.map.aggr=true参数控制在group by的时候是否map局部聚合,这个参数默认是打开的。参数打开后的计算过程如下图。由于map端已经做了局部聚合,虽然还是只有两个reduce做最后的聚合,但是每个reduce只用处理100万行记录,相对优化前的100亿小了1万。
在这里插入图片描述
2>开启数据倾斜时负载均衡

set hive.groupby.skewindata=true//默认关闭
  • 1

hive.groupby.skewindata=true:有数据倾斜的时候进行负载均衡,当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。

详细举例:hive.groupby.skewindata=true:通常这种情况都是在有distinct出现的时候,比如下面的sql: select user.gender,count(distinct user.id) from user group by user.gender ,由于map需要保存所有的user.id , map聚合开关会自动关掉,导致出现计算不均衡的现象,只有2个redcue做聚合,每个reduce处理100亿条记录。
在这里插入图片描述
hive.groupby.skewindata =true参数会把上面的sql翻译成两个MR,第一个MR的reduce_key是gender+id。因为id是一个随机散列的值,因此这个MR的reduce计算是很均匀的,reduce完成局部聚合的工作:
在这里插入图片描述
MR1第二个MR完成最终的聚合,统计男女的distinct id值,数据流如下图所示,每个Map只输出两条记录,因此虽然只有两个redcue计算也没有关系,绝大部分计算量已经在第一个MR完成
在这里插入图片描述
MR2 hive.groupby.skewindata 默认是关闭的,因此如果确定有不均衡的情况,需要手动打开这个开关。当然,并不是所有的有distinct的group by都需要打开这个开关,比如下面的sql:
select id,count (distinct gender) from user group by user.id
select gender,count (distinct id) from user group by user.gender
因为user.id是一个散列的值,因此已经是计算均衡的了,所有的reduce都会均匀计算。只有在group by_key不散列,而distinct_key散列的情况下才需要打开这个开关,其他的情况map聚合优化就足矣。

5)当HiveQL中包含count(distinct)
采用 sum() group by 的方式来替换 count(distinct)完成计算。

2.Hive中的排序关键字有哪些?
sort by ,order by ,distribute by,cluster by
sort by :不是全局排序,对每个reduce内部数据进行排序,对于全局数据结果来说不是排序的。
order by :会对输入做全局排序,因此只有一个reducer(多个reducer无法保证全局有序)。只有一个reducer,会导致当输入规模较大时,需要较长的计算时间。
distribute by :指定分区(这里的分区指的是map reduce过程中的分区),按照指定的字段对数据进行划分输出到不同的reduce中,通常结合sort by使用(注:distribute by必须在sort by之前)。
cluster by :属于distribute by和sort by的组合。当distribute by 和sort by的字段相同时,等同于cluster by,使用cluster by进行替代。

3.hive有哪些方式保存元数据,各有哪些特点?
1)内嵌模式:将元数据保存在本地内嵌的derby数据库中,内嵌的derby数据库每次只能访问一个数据文件,也就意味着它不支持多会话连接。
2)本地模式:将元数据保存在本地独立的数据库中(一般是mysql),这可以支持多会话连接。
3)远程模式:把元数据保存在远程独立的mysql数据库中,避免每个客户端都去安装mysql数据库。
Metastore作用:
  metadata即元数据,元数据包含用Hive创建的database、tabel等的元信息。元数据存储在关系型数据库中。如Derby、MySQL等。
  Metastore的作用是:客户端连接metastore服务,metastore再去连接MySQL数据库来存取元数据。有了metastore服务,就可以有多个客户端同时连接,而且这些客户端不需要知道MySQL数据库的用户名和密码,只需要连接metastore 服务即可。
三种配置方式区别:
  内嵌模式使用的是内嵌的Derby数据库来存储元数据,也不需要额外起Metastore服务。这个是默认的,配置简单,但是一次只能一个客户端连接,适用于用来实验,不适用于生产环境。
  本地元存储和远程元存储都采用外部数据库来存储元数据,目前支持的数据库有:MySQL、Postgres、Oracle、MS SQL Server。
  本地元存储和远程元存储的区别是:本地元存储不需要单独起metastore服务,用的是跟hive在同一个进程里的metastore服务。远程元存储需要单独起metastore服务,然后每个客户端都在配置文件里配置连接到该metastore服务。远程元存储的metastore服务和hive运行在不同的进程。

4.海量数据分布在100台电脑中,想个办法高效统计出这批数据的TOP10。
方案1:
1)在每台电脑上求出TOP10,可以采用包含10个元素的堆完成(TOP10小,用最大堆,TOP10大,用最小堆)。
2)比如求TOP10大,我们首先取前10个元素调整成最小堆,如果发现,然后扫描后面的数据,并与堆顶元素比较,如果比堆顶元素大,那么用该元素替换堆顶,然后再调整为最小堆。
3)最后堆中的元素就是TOP10大。
方案2:
1)求出每台电脑上的TOP10后,然后把这100台电脑上的TOP10组合起来,共1000个数据
2)再利用上面类似的方法求出TOP10就可以了。

4.Hive中追加导入数据的4种方式是什么?请写出简要语法
从本地导入:load data local inpath ‘/home/1.txt’ (overwrite)into table student;
从Hdfs导入:load data inpath ‘/user/hive/warehouse/1.txt’ (overwrite)into table student;
查询导入:create table student1 as select * from student;(也可以具体查询某项数据)
查询结果导入:insert(overwrite)into table staff select * from track_log;

5.Hive导出数据有几种方式?如何导出数据?
1.用insert overwrite导出方式
  1)导出到本地:
  insert overwrite local directory ‘/home/test/1’ row format delimited fields terminated by ‘\t’ select * from staff;(递归创建目录)
  2)导出到HDFS
  insert overwrite directory ‘/user/hive/1/2’ row format delimited fields terminated by ‘\t’ select * from staff;
2.Bash shell覆盖追加导出
例如:$ bin/hive -e ‘select * from staff;’ > /home/export/backup.log
3.Sqoop把hive数据导出到外部

6.hive 内部表和外部表区别?
1)内部表:默认创建的表都是所谓的管理表,有时也被称为内部表。因为这种表Hive会或多或少地控制着数据的生命周期。Hive默认情况下会将这些表的数据存储在由配置 hive.metastore.warehouse.dir(例如,/user/hive/warehouse)所定义的目录的子目录下。 当我们删除一个管理表时,Hive也会删除这个表中数据。管理表不适合和其他工具共享数据。
2)外部表:因为表是外部表,所以Hive并非认为其完全拥有这份数据。删除该表并不会删除掉这份数据,不过描述表的元数据信息会被删除掉。
下面以一个具体的例子说明内部表与外部表的区别。
首先,创建一个外部表:
在这里插入图片描述
将abc.txt中的数据加载到表中。
在这里插入图片描述在这里插入图片描述
在hdfs上可查到
在这里插入图片描述
之后删除此外部表
在这里插入图片描述
查询所有表发现确实没有此表
在这里插入图片描述
但在hdfs上此表仍然存在
在这里插入图片描述
此时,数据在,但表已删除
如果将删除了的表再次创建
在这里插入图片描述
查询表中的数据,表不为空
在这里插入图片描述
说明元数据与实际数据谁先有都可以,可以先在hdfs上存储元数据,再创建表;也可以先创建表,再存储元数据。
接下来创建一个内部表:
在这里插入图片描述
将abc.txt导入此表
在这里插入图片描述
在hdfs上查看
在这里插入图片描述
删除此表
在这里插入图片描述
在hdfs上查看,此表不存在
在这里插入图片描述
由此可见内部表与外部表的区别:内部表删除后,hdfs上的元数据一并删除,而外部表删除后,hdfs上的元数据并未删除。
管理表和外部表的使用场景:
每天将收集到的网站日志定期流入HDFS文本文件。在外部表(原始日志表)的基础上做大量的统计分析,用到的中间表、结果表使用内部表存储,数据通过SELECT+INSERT进入内部表。
3.管理表与外部表的互相转换
1)查询表的类型
在这里插入图片描述
2)修改为内部表
在这里插入图片描述
3)再次查询表的类型
在这里插入图片描述
若将内部表改为外部表,则为’EXTERNAL’='TRUE
注:‘EXTERNAL’=‘TRUE’和’EXTERNAL’='FALSE’为固定写法,区分大小写!

7 分区和分桶的区别?
分区:
指按照数据表的某列或某些列分为多个区,区从形式上可以理解为文件夹,比如我们要收集某个大型网站的日志数据,一个网站每天的日志数据存在同一张表上,由于每天会生成大量的日志,导致数据表的内容巨大,在查询时进行全表扫描耗费的资源非常多。那其实这个情况下,我们可以按照日期对数据表进行分区,不同日期的数据存放在不同的分区,在查询时只要指定分区字段的值就可以直接从该分区查找。

分桶:
分桶是相对分区进行更细粒度的划分。分桶将整个数据内容按照某列属性值得hash值进行区分,如要按照name属性分为3个桶,就是对name属性值的hash值对3取摸,按照取模结果对数据分桶:取模结果为0的数据记录存放到一个文件,取模为1的数据存放到一个文件,取模为2的数据存放到一个文件。

8.Hive优化
1)限制调整:
LIMIT语句是大家经常使用到的,经常使用CLI的用户都会使用到。不过,在很多情况下LIMIT语句还是需要执行整个查询语句,然后再返回部分结果的。因为这种情况通常是浪费的,所以应该尽可能地避免出现这种情况。Hive有-一个配置属性可以开启,当使用LIMTI语句时,其可以对源数据进行抽样:
在这里插入图片描述
一旦属性hive.limit.optimize.enable的值设置为true,那么还会有两个参数可以控制这个操作,也就是hive.limit.row.max.size 和hive.limit.optimize.limit.file:
在这里插入图片描述
这个功能的-一个缺点就是,有可能输人中有用的数据永远不会被处理到,例如,像任意的一个需要reduce步骤的查询,JOIN 和GROUP BY操作,以及聚合函数的大多数调用,等等,将会产生很不同的结果。也许这个差异在很多情况下是可以接受的,但是重要的是要理解。

2)Join优化:
1>每个ON子句使用同一个连接键。当对3个或者更多个表进行JOIN连接时,如果每个ON子句都使用相同的连接键的话,那么只会产生一个MapReduce job。
2>Hive同时假定查询中最后一个表是最大的那个表。在对每行记录进行连接操作时,它会尝试将其他表缓存起来,然后扫描最后那个表进行计算。因此,用户需要保证连续查询中的表的大小从左到右是依次增加的。或者使用Hive提供的“标记”机制来显式地告之查询优化器哪张表是大表,使用方式如下:
在这里插入图片描述
现在Hive将会尝试将表stocks 作为驱动表,即使其在查询中不是位于最后面的。
3>map-side join:如果所有表中只有一张表是小表,那么可以在最大的表通过mapper的时候将小表完全放到内存中。Hive可以在map端执行连接过程(称为map-side JOIN),这是因为Hive可以和内存中的小表进行逐一匹配,从而省略掉常规连接操作所需要的reduce过程。即使对于很小的数据集,这个优化也明显地要快于常规的连接操作。其不仅减少了reduce过程,而且有时还可以同时减少map过程的执行步骤。
在Hive v0.7之前的版本中,如果想使用这个优化,需要在查询语句中增加一个标记来进行触发。如下面的这个内连接(INNER JOIN)的例子所示:
在这里插入图片描述
从Hive v0.7 版本开始,废弃了这种标记的方式,不过如果增加了这个标记同样是有效的。如果不加上这个标记,那么这时用户需要设置属性hive.auto.convertJOIN 的值为true, 这样Hive才会在必要的时候启动这个优化。默认情况下这个属性的值是false。
在这里插入图片描述
需要注意的是,用户也可以配置能够使用这个优化的小表的大小。如下是这个属性的默认值(单位是字节):
在这里插入图片描述
如果用户期望Hive在必要的时候自动启动这个优化的话,那么可以将这-一个(或两个)属性设置在SHOME/.hiverc文件中。Hive对于右外连接(RIGHT OUTER JOIN)和全外连接(FULL OUTER JOIN)不支持这个优化。
3)本地模式:
大多数的Hadoop Job是需要Hadoop提供的完整的可扩展性来处理大数据集的。不过,有时Hive的输人数据量是非常小的。在这种情况下,为查询触发执行任务的时间消耗可能会比实际job的执行时间要多得多。对于大多数这种情况,Hive 可以通过本地模式在单台机器上(或某些时候在单个进程中)处理所有的任务。对于小数据集,执行时间可以明显被缩短。
用户可以按照如下这个例子中所演示的方式,在执行过程中临时启用本地模式:
在这里插入图片描述
用户可以通过设置属性hive.exec.mode.local.auto的值为true,来让Hive在适当的时候自动启动这个优化。通常用户可以将这个配置写在8HOME/.hiverc文件中。如果希望对所有的用户都使用这个配置,那么可以将这个配置项增加到SHIVE_ HOME/conf/hive-site.xml文件中:
在这里插入图片描述
4)并行执行:
Hive会将-一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段,或者Hive执行过程中可能需要的其他阶段。默认情况下,Hive一次只会执行一个阶段。不过,某个特定的job可能包含众多的阶段,而这些阶段可能并非完全互相依赖的,也就是说有些阶段是可以并行执行的,这样可能使得整个job的执行时间缩短。不过,如果有更多的阶段可以并行执行,那么job可能就越快完成。
通过设置参数hive.exec.parallel值为true,就可以开启并发执行。不过,在共享集群中,需要注意下,如果job中并行执行的阶段增多,那么集群利用率就会增加:
在这里插入图片描述
5)严格模式
Hive提供了一个严格模式,可以防止用户执行那些可能产生意想不到的不好的影响的查询。
通过设置属性hive.mapred.mode值为strict可以禁止3种类型的查询。
其一,对于分区表,除非WHEHRE语句中含有分区字段过滤条件来限制数据范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表:
在这里插入图片描述
如下这个语句在WHERE语句中增加了一个分区过滤条件(也就是限制了表分区):
在这里插入图片描述
其二,对于使用了ORDER BY语句的查询,要求必须使用LIMIT语句。因为ORDER BY为了执行排序过程会将所有的结果数据分发到同一个reducer中进行处理,强制要求用户增加这个LIMIT语句可以防止reducer额外执行很长一段时间:
在这里插入图片描述
只需要增加LIMIT语句就可以解决这个问题:
在这里插入图片描述
其三,也就是最后一种情况,就是限制笛卡尔积的查询。对关系型数据库非常了解的用户可能期望在执行JOIN查询的时候不使用ON语句而是使用WHERE语句,这样关系型数据库的执行优化器就可以高效地将WHERE语句转化成那个ON语句。不幸的是,Hive并不会执行这种优化,因此,如果表足够大,那么这个查询就会出现不可控的情况:
在这里插入图片描述
下面这个才是个正确的使用JOIN和ON语句的查询:
在这里插入图片描述
6)调整mapper和reducer个数
Hive通过将查询划分成-一个或者多个MapReduce任务达到并行的目的。每个任务都可能具有多个mapper和reducer 任务,其中至少有一些是可以并行执行的。确定最佳的mapper个数和reducer个数取决于多个变量,例如输人的数据量大小以及对这些数据执行的操作类型等。
保持平衡性是有必要的。如果有太多的mapper或reducer任务,就会导致启动阶段、调度和运行job过程中产生过多的开销;而如果设置的数量太少,那么就可能没有充分利用好集群内在的并行性。
当执行的Hive查询具有reduce过程时,CLI 控制台会打印出调优后的reducer个数。下面我们来看一个包含有GROUP BY语句的例子,因为这种查询总是需要reduce过程的。与此相反,很多其他查询会转换成只需要map阶段的任务:
在这里插入图片描述
Hive是按照输人的数据量大小来确定reducer个数的。我们可以通过dfs - count命令来计算输人量大小,这个命令和Linux中的du -s命令类似;其可以计算指定目录下所有数据的总大小:
在这里插入图片描述
属性hive.exec.reducers.bytes.per.reducer 的默认值是1GB。 如果将这个属性值调整为750MB的话,那么下面这个任务Hive就会使用4个reducer:
在这里插入图片描述
默认值通常情况下是比较合适的。不过,有些情况下查询的map阶段会产生比实际输入数据量要多得多的数据。如果map阶段产生的数据量非常多,那么根据输人的数据量大小来确定的reducer个数就显得有些少了。同样地,map阶段也可能会过滤掉输入数据集中的很大一部分的数据而这时可能需要少量的reducer就满足计算了。
一个快速的进行验证的方式就是将reducer 个数设置为固定的值,而无需Hive来计算得到这个值。如果用户还记得的话,Hive 的默认reducer个数应该是3。可以通过设置属性mapred.reduce.tasks 的值为不同的值来确定是使用较多还是较少的reducer来缩短执行时间。需要记住,受外部因素影响,像这样的标杆值十分复杂,例如其他用户并发执行job的情况。Hadoop需要消耗好几秒时间来启动和调度map和reduce任务(task)。 在进行性能测试的时候,要考虑到这些影响因子,特别是job比较小的时候。
当在共享集群上处理大任务时,为了控制资源利用情况,属性hive.exec.reducers.max显得非常重要。一个Hadoop集群可以提供的map和reduce 资源个数(也称为“插槽”),是固定的。某个大job可能就会消耗完所有的插槽,从而导致其他job无法执行。通过设置属性hive.exec.reducers.max可以阻止某个查询消耗太多的reducer资源。有必要将这个属性配置到$HIVE_ HOME/confhive-site.xml 文件中。对这个属性值大小的一个建议的计算公式如下:
(集群总Reduce槽位个数*1.5) / (执行中的查询的平均个数)
1.5倍数是一个经验系数,用于防止未充分利用集群的情况。

7)JVM重用
JVM重用是Hadoop调优参数的内容,其对Hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或task特别多的场景,这类场景大多数执行时间都很短。Hadoop的默认配置通常是使用派生JVM来执行map和reduce任务的。这时JVM的启动过程可能会造成相当大的开销,尤其是执行的job包含有成百上千个task任务的情况。JVM重用可以使得JVM实例在同一一个job中重新使用N次。N的值可以在Hadoop的mapred-site.xml文件(位于 $ HADOOP_ HOME/conf 目录下)中进行设置:
在这里插入图片描述
这个功能的一一个缺点是,开启JVM重用将会- -直占用使用到的task插槽,以便进行重用,直到任务完成后才能释放。如果某个“不平衡的”的job中有某几个reduce task执行的时间要比其他reduce task 消耗的时间多得多的话,那么保留的插槽就会一直空闲着却无法被其他的job使用,直到所有的task都结束了才会释放。

8)索引
索引可以用来加快含有GROUP BY语句的查询的计算速度。Hive从v0.8.0版本后增加了一个bitmap索引实现。Bitmap索引一般在指定的列排重后的值比较小时进行使用。例:
在这里插入图片描述
9)动态分区调整
动态分区INSERT语句可以通过简单的SELECT语句向分区表中创建很多新的分区。这是-一个非常强大的功能,不过如果分区的个数非常得多,那么就会在系统中产生大量的输出控制流。对于Hadoop来说,这种情况并不是常见的使用场景,因此,其通常会一次创建很多的文件,然后会向这些文件中写人大量的数据。
跳出这些框框, Hive可以通过配置限制动态分区插入允许创建的分区数在1000个左右。虽然太多的分区对于表来说并不好,不过,通常还是将这个值设置的更大以便这些查询执行。
首先,通常在hive- site.xml配置文件中设置动态分区模式为严格模式(也就是属性值为strict), 开启严格模式的时候,必须保证至少有一个分区是静态的。
在这里插入图片描述
然后,可以增加一些相关的属性信息,例如通过如下属性来限制查询可以创建的最大动态分区个数:
在这里插入图片描述
在这里插入图片描述
还有一个配置是来控制DataNode上一次可以打开的文件的个数。这个参数必须设置在DataNode的$HADOOP_ HOME/conf/hdfs-site.xml 配置文件中。
在Hadoop v0.20.2版本中,这个属性的默认值是256,太小了。这个值会影响到最大的线程数和资源数,因此,也并不推荐将这个属性值设置为-一个极大值。同时需要注意的是,在Hadoop v0.20.2版本中,更改这个属性值需要重启DataNode才能够生效:
在这里插入图片描述
10)推测执行
推测执行是Hadoop中的-一个功能,其可以触发执行一-些重复的任务 (task)。 尽管这样会因对重复的数据进行计算而导致消耗更多的计算资源,不过这个功能的目标是通过加快获取单个task的结果以及进行侦测将执行慢的TaskTracker加人到黑名单的方式来提高整体的任务执行效率。
Hadoop的推测执行功能由 $HADOOP_ HOME/conf/mapred-site.xml 文件中的如下2个配置项控制着:
在这里插入图片描述
不过,Hive 本身也提供了配置项来控制reduce-side的推测执行:
在这里插入图片描述
在这里插入图片描述
关于调优这些推测执行变量,还很难给一个具体的建议。如果用户对于运行时的偏差非常敏感的话,那么可以将这些功能关闭掉。如果用户因为输入数据量很大而需要执行长时间的map或者reduce task的话,那么启动推测执行造成的浪费是非常巨大的。

11)单个MapReduce中多个GROUP BY
另一个特别的优化试图将查询中的多个GROUPBY操作组装到单个MapReduce任务中。如果想启动这个优化,那么需要一-组常用的GROUP BY键:
在这里插入图片描述
12)虚拟列
Hive提供了2种虚拟列:一 种用于将要进行划分的输人文件名,另-种用于文件中的块内偏移量。当Hive产生了非预期的或null的返回结果时,可以通过这些虚拟列诊断查询。通过查询这些”字段”,用户可以查看到哪个文件甚至哪行数据导致出现问题:
在这里插入图片描述
第3种虛拟列提供了文件的行偏移量。这个需要通过如下参数显式地启用:
在这里插入图片描述
这样设置后就可以在类似于如下的查询中使用了
在这里插入图片描述

参考:https://blog.csdn.net/wxfghy/article/details/81361400
Hive优化:
1.通用设置
hive.optimize.cp=true:列裁剪
hive.optimize.prunner:分区裁剪
hive.limit.optimize.enable=true:优化LIMIT n语句
hive.limit.row.max.size=1000000:
hive.limit.optimize.limit.file=10:最大文件数

2.本地模式(小任务)
1)job的输入数据大小必须小于参数:hive.exec.mode.local.auto.inputbytes.max(默认128MB)
2)job的map数必须小于参数:hive.exec.mode.local.auto.tasks.max(默认4)
3)job的reduce数必须为0或者1
   hive.exec.mode.local.auto.inputbytes.max=134217728
   hive.exec.mode.local.auto.tasks.max=4
   hive.exec.mode.local.auto=true
   hive.mapred.local.mem:本地模式启动的JVM内存大小

3.并发执行
hive.exec.parallel=true ,默认为false
hive.exec.parallel.thread.number=8

4.Strict Mode:
hive.mapred.mode=true,严格模式不允许执行以下查询:
分区表上没有指定了分区
没有limit限制的order by语句
笛卡尔积:JOIN时没有ON语句

5.动态分区
hive.exec.dynamic.partition.mode=strict:该模式下必须指定一个静态分区
hive.exec.max.dynamic.partitions=1000
hive.exec.max.dynamic.partitions.pernode=100:在每一个mapper/reducer节点允许创建的最大分区数
DATANODE:dfs.datanode.max.xceivers=8192:允许DATANODE打开多少个文件

6.推测执行
mapred.map.tasks.speculative.execution=true
mapred.reduce.tasks.speculative.execution=true
hive.mapred.reduce.tasks.speculative.execution=true;

7.多个group by合并
hive.multigroupby.singlemar=true:当多个GROUP BY语句有相同的分组列,则会优化为一个MR任务

8.虚拟列
hive.exec.rowoffset:是否提供虚拟列

9.分组
1)两个聚集函数不能有不同的DISTINCT列,以下表达式是错误的:
INSERT OVERWRITE TABLE pv_gender_agg SELECT pv_users.gender, count(DISTINCT pv_users.userid), count(DISTINCT pv_users.ip) FROM pv_users GROUP BY pv_users.gender;
2)SELECT语句中只能有GROUP BY的列或者聚集函数。

10.Combiner聚合
hive.map.aggr=true;在map中会做部分聚集操作,效率更高但需要更多的内存。
hive.groupby.mapaggr.checkinterval:在Map端进行聚合操作的条目数目

11.数据倾斜
1)hive.groupby.skewindata=true:数据倾斜时负载均衡,当选项设定为true,生成的查询计划会有两个MRJob。
2)第一个MRJob 中,Map的输出结果集合会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的GroupBy Key
有可能被分发到不同的Reduce中,从而达到负载均衡的目的;
3)第二个MRJob再根据预处理的数据结果按照GroupBy Key分布到Reduce中(这个过程可以保证相同的GroupBy Key被分布到同一个Reduce中),最后完成最终的聚合操作。

12.排序
ORDER BY colName ASC/DESC
hive.mapred.mode=strict时需要跟limit子句
hive.mapred.mode=nonstrict时使用单个reduce完成排序
SORT BY colName ASC/DESC :每个reduce内排序
DISTRIBUTE BY(子查询情况下使用 ):控制特定行应该到哪个reducer,并不保证reduce内数据的顺序
CLUSTER BY :当SORT BY 、DISTRIBUTE BY使用相同的列时。

13.合并小文件
hive.merg.mapfiles=true:合并map输出
hive.merge.mapredfiles=false:合并reduce输出
hive.merge.size.per.task=256*1000*1000:合并文件的大小
hive.mergejob.maponly=true:如果支持CombineHiveInputFormat则生成只有Map的任务执行merge
hive.merge.smallfiles.avgsize=16000000:文件的平均大小小于该值时,会启动一个MR任务执行merge。

14.自定义map/reduce数目
1)减少map数目:
  set mapred.max.split.size
  set mapred.min.split.size
  set mapred.min.split.size.per.node
  set mapred.min.split.size.per.rack
  set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat
2)增加map数目:
1>当input的文件都很大,任务逻辑复杂,map执行非常慢的时候,可以考虑增加Map数,来使得每个map处理的数据量减少,从而提高任务的执行效率。
2>假设有这样一个任务:
select data_desc, count(1), count(distinct id),sum(case when …),sum(case when ...),sum(…) from a group by data_desc
3>如果表a只有一个文件,大小为120M,但包含几千万的记录,如果用1个map去完成这个任务,肯定是比较耗时的,这种情况下,我们要考虑将这一个文件合理的拆分成多个,这样就可以用多个map任务去完成。
  set mapred.reduce.tasks=10;
  create table a_1 as select * from a distribute by rand(123);
4>这样会将a表的记录,随机的分散到包含10个文件的a_1表中,再用a_1代替上面sql中的a表,则会用10个map任务去完成。每个map任务处理大于12M(几百万记录)的数据,效率肯定会好很多。
3)reduce数目设置:
1>参数1:hive.exec.reducers.bytes.per.reducer=1G:每个reduce任务处理的数据量
2>参数2:hive.exec.reducers.max=999(0.95*TaskTracker数):每个任务最大的reduce数目
3>reducer数=min(参数2,总输入数据量/参数1)
4>set mapred.reduce.tasks:每个任务默认的reduce数目。典型为0.99*reduce槽数,hive将其设置为-1,自动确定reduce数目。

15.使用索引:
hive.optimize.index.filter:自动使用索引
hive.optimize.index.groupby:使用聚合索引优化GROUP BY操作
  • 1

9.简要描述数据库中的 null,说出null在hive底层如何存储,并解释 select a. * from t1 a left outer join t2 b on a.id=b.id where b.id is null; 语句的含义。
1)null与任何值运算的结果都是null, 可以使用is null、is not null函数指定在其值为null情况下的取值。
2)null在hive底层默认是用’\N’来存储的,可以通过alter table test SET SERDEPROPERTIES(‘serialization.null.format’ = ‘a’);来修改。
3)查询出t1表中与t2表中id相等的所有信息。

10.写出hive中split、coalesce及collect_list函数的用法(可举例)。
split将字符串转化为数组。
split(‘a,b,c,d’ , ‘,’) ==> [“a”,“b”,“c”,“d”]
COALESCE(T v1, T v2, …) 返回参数中的第一个非空值;如果所有值都为 NULL,那么返回NULL。
collect_list列出该字段所有的值,不去重 select collect_list(id) from table;

11.写出将 text.txt 文件放入 hive 中 test 表‘2016-10-10’ 分区的语句,test 的分区字段是 l_date。

LOAD DATA LOCAL INPATH '/your/path/test.txt' OVERWRITE INTO TABLE test PARTITION (l_date='2016-10-10')
  • 1

12.Multi-group by 是hive的一个非常好的特性,请举例说明?
multi group by 可以将查询中的多个group by操作组装到一个MapReduce任务中,起到优化作用。

例子:

select Provice,city,county,count(rainfall) from area where data="2018-09-02" group by provice,city,count

select Provice,count(rainfall) from area where data="2018-09-02" group by provice
  • 1
  • 2
  • 3

使用multi group by:

from area

insert overwrite table temp1

select Provice,city,county,count(rainfall) from area where data="2018-09-02" group by provice,city,count

insert overwrite table temp2

select Provice,count(rainfall) from area where data="2018-09-02" group by provice

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

使用multi group by 之前必须配置参数:

<property>

    <name>hive.multigroupby.singlemr</name>

    <value>true</value>

</property>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

13.请谈一下hive的特点是什么?hive和RDBMS有什么异同?
hive由Facebook开源用于解决海量结构化日志的数据统计,是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供完整的sql查询功能,可以将sql语句转换为MapReduce任务进行运行。其优点是学习成本低,可以通过类SQL语句快速实现简单的MapReduce统计,不必开发专门的MapReduce应用,十分适合数据仓库的统计分析。

在这里插入图片描述
1)hive存储的数据量比较大,适合海量数据,适合存储轨迹类历史数据,适合用来做离线分析、数据挖掘运算,事务性较差,实时性较差。rdbms一般数据量相对来说不会太大,适合事务性计算,实时性较好,更加接近上层业务。

2)hive的计算引擎是hadoop的mapreduce,存储是hadoop的hdfs文件系统。rdbms的引擎由数据库自己设计实现例如mysql的innoDB,存储用的是数据库服务器本地的文件系统。

3)hive由于基于hadoop所以存储和计算的扩展能力都很好,rdbms在这方面比较弱,比如orcale的分表和扩容就很头疼。

4)hive表格没有主键、没有索引、不支持对具体某一行的操作,适合对批量数据的操作,不支持对数据的update操作,更新的话一般是先删除表然后重新落数据rdbms事务性强,有主键、索引,支持对具体某一行的增删改查等操作。

5)hive的SQL为HQL,与标准的RDBMS的SQL存在有不少的区别,相对来说功能有限rdbms的SQL为标准SQL,功能较为强大。

6)Hive在加载数据时候和rdbms关系数据库不同,hive在加载数据时候不会对数据进行检查,也不会更改被加载的数据文件,而检查数据格式的操作是在查询操作时候执行,这种模式叫“读时模式”。在实际应用中,写时模式在加载数据时候会对列进行索引,对数据进行压缩,因此加载数据的速度很慢,但是当数据加载好了,我们去查询数据的时候,速度很快。但是当我们的数据是非结构化,存储模式也是未知时候,关系数据操作这种场景就麻烦多了,这时候hive就会发挥它的优势。

rdbms里,表的加载模式是在数据加载时候强制确定的(表的加载模式是指数据库存储数据的文件格式),如果加载数据时候发现加载的数据不符合模式,关系数据库则会拒绝加载数据,这个就叫“写时模式”,写时模式会在数据加载时候对数据模式进行检查校验的操作。

总结:Hive并非为联机事务处理而设计,Hive并不提供实时的查询和基于行级的数据更新操作。Hive是建立在Hadoop之上的数据仓库软件工具,它提供了一系列的工具,帮助用户对大规模的数据进行提取、转换和加载,即通常所称的ETL(Extraction,Transformation,and Loading)操作。Hive可以直接访问存储在HDFS或者其他存储系统(如Hbase)中的数据,然后将这些数据组织成表的形式,在其上执行ETL操作。 HIVE是数据仓库适合存储历史的海量的数据,适合做批量和海量复杂运算,事务性差,运算时间长。RDBMS是数据库,存储数据量偏小一些,事务性强,适合做OLTP和OLAP业务,运算时间短。Hive的最佳使用场合是大数据集的批处理作业,例如,网络日志分析。

● 1)查询语言。
由于SQL被广泛的应用在数据仓库中,因此,专门针对Hive的特性设计了类SQL的查询语言HQL。熟悉SQL开发的开发者可以很方便的使用Hive进行开发。
● 2)数据存储位置。
Hive是建立在Hadoop之上的,所有Hive的数据都是存储在HDFS中的。而数据库则可以将数据保存在块设备或者本地文件系统中。
● 3)数据更新。
由于Hive是针对数据仓库应用设计的,而数据仓库的内容是读多写少的。因此,Hive中不建议对数据的改写,所有的数据都是在加载的时候确定好的。而数据库中的数据通常是需要经常进行修改的,因此可以使用INSERT NT0.... VALUES添加数据,使用UPDATE...SET修改数据。
● 4)索引。
Hive在加载数据的过程中不会对数据进行任何处理,甚至不会对数据进行扫描,因此也没有对数据中的某些Key建立索引。Hive 要访问数据中满足条件的特定值时,需要暴力扫描整个数据,因此访问延迟较高。由于MapReduce的引入,Hive 可以并行访问数据,因此即使没有索引,对于大数据量的访问,Hive 仍然可以体现出优势。数据库中,通常会针对一个或者几个列建立索引,因此对于少量的特定条件的数据的访问,数据库可以有很高的效率,较低的延迟。由于数据的访问延迟较高,决定了Hive 不适合在线数据查询。
● 5)执行。
Hive中大多数查询的执行是通过Hadoop提供的MapReduce来实现的。而数据库通常有自己的执行引擎。
● 6)执行延迟。
Hive在查询数据的时候,由于没有索引,需要扫描整个表,因此延迟较高。另外一个导致Hive执行延迟高的因素是MapReduce框架。由于MapReduce 本身具有较高的延迟,因此在利用MapReduce执行Hive查询时,也会有较高的延迟。相对的,数据库的执行延迟较低。当然,这个低是有条件的,即数据规模较小,当数据规模大到超过数据库的处理能力的时候,Hive 的并行计算显然能体现出优势。
● 7)可扩展性。
由于Hive是建立在Hadoop之上的,因此Hive的可扩展性是和Hadoop的可扩展性是一致的(世界上最大的Hadoop集群在Yahoo!, 2009 年的规模在4000台节点左右)。而数据库由于ACID语义的严格限制,扩展行非常有限。目前最先进的并行数据库Oracle在理论上的扩展能力也只有100台左右。
● 8)数据规模。
由于Hive建立在集群上并可以利用MapReduce进行并行计算,因此可以支持很大规模的数据;对应的,数据库可以支持的数据规模较小。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

14.hive架构
在这里插入图片描述
1.用户接口: Client
CLI (hive shell)、JDBC/ODBC(java访问hive)、WEBUI (浏览器访问hive)。
2.元数据: Metastore。
元数据包括:表名、表所属的数据库(默认是default) 、表的拥有者、列/分区字段、表的类型(是否是外部表)、表的数据所在目录等;
默认存储在自带的derby数据库中,推荐使用MySQL存储Metastore
3.Hadoop。
使用HDFS进行存储,使用MapReduce进行计算。。
4.驱动器: Drivers
(1)解析器(SQL Parser):将SQL字符串转换成抽象语法树AST,这一步一般都用第三方工具库完成,比如antlr;对AST进行语法分析,比如表是否存在、字段是否存在、SQL语义是否有误。
(2)编译器(Physical Plan):将AST编译生成逻辑执行计划。。
(3)优化器(Query Optimizer):对逻辑执行计划进行优化。
(4)执行器(Execution):把逻辑执行计划转换成可以运行的物理计划。对于Hive来说,就是MR/Spark。
在这里插入图片描述

参考:https://blog.csdn.net/qq_35036995/article/details/80298403
   https://blog.csdn.net/u011317245/article/details/53977771

posted @ 2020-10-19 17:16  十一vs十一  阅读(2261)  评论(0编辑  收藏  举报