Hive知识归纳——详解 hive 各个知识点

有点标题党了,但是大部分常用知识点也算是涉及到了,希望对你有帮助

Hive是什么?

概念

  •    从概念上讲:由Facebook开源的一款基于hadoop的用于统计海量结构化数据的一个数据仓库。
  •   从本质上讲:将HQL语句转换成MapReduce程序的一个工具。

产生:

  • 让了方便非java开发人员对hdfs上的数据做 MapReduce 操作

架构

  1. 从客户端编辑 sql 语句提交到服务端,通过解释器,编译器,优化器生成执行计划,然后提交到 Hadoop 集群运行

其中计划执行的最小单元是一个个 operator,每个operator代表一个操作或者一个MR作业

  1. Hive的元数据依赖于关系型数据库,其真实数据是存在于Hadoop之上的

  2. 下图为 Hive 架构简图,其中 Hadoop 展示的是 1.x 版本的,2.x 以后是提交到 yarn上运行。

    《Hive知识归纳——详解 hive 各个知识点》 image.png

支持的数据类型

  1. 复杂类型
    | array_type
    | map_type
    | struct_type
  2. 简单类型
    |TINYINT
    | SMALLINT
    | INT
    | BIGINT
    | BOOLEAN
    | FLOAT
    | DOUBLE
    | STRING

表的类型

  1. 外部表:删除表时,只会删除元数据信息,而不对真实数据进行修改
  2. 内部表:也叫管理表,删除表时,会对元数据和真实数据一起删除。

HIve分区

  • 意义
  1. 其意义主要在于优化查询,对于分区表,我们一般都要求使用分区字段进行过滤,以加快查询速度
  • 静态分区使用
  1. 建表是指定分区(其中分区在hdfs上表现为文件夹分类管理形式)

create table day_hour_table (id int, content string) partitioned by (dt string, hour string);

  1. 在已有的表上添加分区

ALTER TABLE table_name ADD PARTITION (dt=’2018-06-02′, hour=’18’)

  1. 在已有表上删除某分区

ALTER TABLE table_name DROP PARTITION (dt=’2018-06-02′, hour=’18’)

  1. 向分区表中添加数据:

LOAD DATA INPATH “/testFile” INTO TABLE table_name PARTITION(dt=’2018-06-02′, hour=’18’)

  • 动态分区
  1. 开启支持动态分区

set hive.exec.dynamic.partition=true;
默认:false

set hive.exec.dynamic.partition.mode=nostrict;
默认:strict(至少有一个分区列是静态分区)

  1. 相关参数

set hive.exec.max.dynamic.partitions.pernode;
每一个执行mr节点上,允许创建的动态分区的最大数量(100)
set hive.exec.max.dynamic.partitions;
所有执行mr节点上,允许创建的所有动态分区的最大数量(1000)
set hive.exec.max.created.files;
所有的mr job允许创建的文件的最大数量(100000)

  1. 加载数据

from table_name1
insert overwrite table table_name2 partition(age, sex)
select id, name, age, sex, address distribute by age, sex;

hive 分桶

  • 分桶表是对列值取哈希值的方式,将不同数据放到不同文件中存储。
    对于hive中每一个表、分区都可以进一步进行分桶。
    由列的哈希值除以桶的个数来决定每条数据划分在哪个桶中。

  • 适用场景:
    数据抽样( sampling )、map-join

  1. 开启支持分桶

set hive.enforce.bucketing=true;
默认:false;设置为true之后,mr运行时会根据bucket的个数自动分配reduce task个数。(用户也可以通过mapred.reduce.tasks自己设置reduce任务个数,但分桶时不推荐使用)
注意:一次作业产生的桶(文件数量)和reduce task个数一致。

  1. 创建分桶表

CREATE TABLE tb_name( id INT, name STRING, age INT)
CLUSTERED BY (age) INTO 4 BUCKETS
ROW FORMAT DELIMITED FIELDS TERMINATED BY ‘,’;

  1. 加载数据:

insert into table tb_name select id, name, age from source_tb_name;

  1. 抽样

select id, name, age from tb_name tablesample(bucket 1 out of 2 on age);
一共4个桶,抽取2(4/2)个bucket的数据,抽取第1、第3(1+2)个bucket的数据

Beeline 和 HIveServer2

  • beeline 要与 HIveServer2 配合使用
  • 服务端启动 HIveServer2
  • 客户端可以通过beeline -u jdbc:hive2://hostname:10000/db_name -n username 进行hive的连接
  • HiveServer2的另外一个功能,就是提供给开发者一个jdbc的开发接口
  • HiveServer2 相比 Hive MetaServer 是很好的隐藏了客户端,这一点亲手配置过 Hive 的同学可能比较能够理解,因为 beeline 其实是不需要任何配置的,连上 hiveserver2 就能用,但是 Hive MetaServer 是需要你自己配置 Hive客户端的。并且高可用的配置只能基于 HiveServer2

Hive 函数

  • UDTF:一进多出函数,对于某个数据经过函数会产生多条记录,eg: explode
  • UDF:一进一出函数,对于一个数据经过函数处理,还是一条数据 eg: to_date
  • UDAF:多进一出函数,多条数据经过函数处理会聚合成一条数据 eg: count
  • 这块内容其实挺多的,但是官网都有详细的文档,所以下面只是简单的给出官网链接,偷懒一把!!!嘿嘿
  • 自定义 UDF
    1. UDF
    2. UDTF
    3. UDAF
    4. 创建永久和临时函数

Hive 索引

  • 目的:优化查询以及检索性能
  1. 创建索引:

create index t1_index on table tb_name1(name)
as ‘org.apache.hadoop.hive.ql.index.compact.CompactIndexHandler’ with deferred rebuild
in table t1_index_table;
as:指定索引器;
in table:指定索引表,若不指定默认生成在default__psn2_t1_index__表中

  1. 查询索引
    show index on tb_name1;

  2. 重建索引(建立索引之后必须重建索引才能生效)
    ALTER INDEX t1_index ON tb_name1 REBUILD;

  3. 删除索引
    DROP INDEX IF EXISTS t1_index ON tb_name1;

5.使用的时候根据索引条件查询能加快查询速度,但是由于索引表也是需要维护的,会带来额外开销。

  1. 实际上,hive作为数据仓库,其实索引的使用还是比较少的,反正我是没怎么使用过。。。

数据倾斜

  • 什么时数据倾斜?什么导致的数据倾斜?
  1. 一般来说,在分布式计算系统中,我们期望的每个节点完成任务的时间是一致的,但是实际生产环境中,因为种种原因会导致某些节点处理的数据较大,导致完成任务时间与其他节点相差很大,导致整个任务完成时间过长,这就是我们常说的数据倾斜

  2. 一般来说,导致数据倾斜的原因都是因为数据分布的不均匀导致的,而 Hive 因为底层是通过 MR 实现的,所以数据倾斜一般都是发生在 Reduce 端,而 Reduce 端处理的数据是由我们的 Partition 决定的,这就为我们寻找数据倾斜的原因提供了一个最基本的思路。

3.默认的我们 partition 都是通过 key 来决定的,所以一般导致数据倾斜的原因都是 key 的分布不均匀,同时也采用了一些可能会导致数据倾斜的操作,比如 group by , join 等。

  • 数据倾斜解决方案

    1. Hive自带的数据倾斜解决方案,主要是针对 group by ;

    a. 设置参数 :set hive.map.aggr=true ,开启 map 端的聚合功能,也就是 MR 程序中写的 combiner

    1. hive.groupby.mapaggr.checkinterval:
      map端group by执行聚合时处理的多少行数据(默认:100000),
    2. hive.map.aggr.hash.min.reduction:
      进行聚合的最小比例(预先对100000条数据做聚合,若 (聚合之后的数据量)/100000 的值大于该配置设 置值0.5,则不会聚合)
    3. hive.map.aggr.hash.percentmemory:
      map端聚合使用的内存的最大值
    4. hive.map.aggr.hash.force.flush.memory.threshold:
      map端做聚合操作是hash表的最大可用内容,大于该值则会触发flush

    b. 设置 set hive.groupby.skewindata=true ,开启Group By 产生数据倾斜优化

    该处理方式是将一次group 操作进行了两次处理,首先会对map端输入的数据进行随机分发给reduce端,因为是随机的,所以数据会均匀分发给reduce 进行 group ,然后对第一次group处理的数据再进行一次正常的 group操作,因为有了第一次的处理,第二次处理的数据将会大大减少,从而使得数据倾斜问题不再明显。严格来说,这并没有解决数据倾斜问题,但是却大大减少了数据倾斜带来的影响

    1. Join产生的数据倾斜
      a. Map端进行join:适合小表 join 大表的情况
    1. 通过修改以下配置启用自动的mapjoin:
      set hive.auto.convert.join = true;
      (该参数为true时,Hive自动对左边的表统计量,如果是小表就加入内存,即对小表使用Map join)
    2. hive.mapjoin.smalltable.filesize;
      (大表小表判断的阈值,如果表的大小小于该值则会被加载到内存中运行)
    3. hive.ignore.mapjoin.hint;
      (默认值:true;是否忽略mapjoin hint 即HQL 语句中的 mapjoin 标记)
    4. hive.auto.convert.join.noconditionaltask;
      (默认值:true;将普通的join转化为普通的mapjoin时,是否将多个mapjoin转化为一个mapjoin)
    5. hive.auto.convert.join.noconditionaltask.size;
      (将多个mapjoin转化为一个mapjoin时,其表的最大值)

    b. 对于两张都是大表的情况,我们可以想办法将一个大表转化为小表,然后采用 a 方案;另外我们也可以使用分桶的思想,将导致数据倾斜的 key 过滤出来额外处理。其中 https://blog.csdn.net/s646575997/article/details/51510661 这上面有些案例可以参考,

HIve 优化

谈起优化,上面很大一部分内容都有涉及,这里我们主要谈谈 HQL 优化

  1. 某些容易导致数据倾斜的函数
  • count(distinct *)
    该用法在MR 的 reduce 阶段只有一个 reduce 来处理,当数据量较大会导致严重的数据倾斜。
    可以通过
    select count(1) from (select distinct(uid) d_uid from t)
    来优化
  • order by key
    对于全局排序也有上面类似的问题
    为了解决上面的问题,我们需要先了解下hive的几种排序
    order by:全局排序,一般不用
    cluster by:全局排序,建议使用,但是只能是降序,不能指定asc和desc
    sort by:局部排序,这个局部就是每个 reduce 内部,所以不能保证全局有序,单个使用意义不大,需要结合 distribute by一起使用
    distribute by:分区排序,在分发数据给 reduce 的时候保证 reduce 是有序的,结合 sort by,可以做到全局有序
    所以上面这个问题可以通过
    select a,b,c from t distribute by a sort by a asc, b desc
    来解决
  1. Union All insert
//union all
insert overwrite table t
select a,b,c   
from t1      
union all   
select a,b,c from t2

//普通方式
insert overwrite table t
select a,b,c  from t1
insert overwrite table t
select a,b,c  from t2
  1. limit
    limit 限制,对于hive 很多时候都是需要进行全表统计,然后显示 limit 限制的条数的记录,对于执行速度并没有多大的提升,如果我们的需求是可以通过抽样来看整体情况的,那么全表扫描无疑是很浪费资源的,所以hive也是提供了相应的优化机制,来允许我们采用抽样使用 limit
    hive.limit.optimize.enable=true --- 开启对数据源进行采样的功能
    hive.limit.row.max.size --- 设置最小的采样容量
    hive.limit.optimize.limit.file --- 设置最大的采样样本数

  2. join

  • 多个join 相互关联,尽可能的使用相同的 key 进行关联,这样就 Hive 就只会使用一个 Maper 去操作
  • 还有就是上文说的 小表 join 大表 的情况了
  1. 本地执行
    当我们觉得有些任务是杀鸡用牛到的时候,可以尝试运用本地运行,分布式计算只有再数据量足够大的时候才能体现其优势,否则单机是更快的。
    通过 mapred.job.tracker=true 参数开启本地模式
    当然,hive 也提供了自动开启本地模式的优化机制
    通过 hive.exec.mode.local.auto开启自动执行,自动开启的条件如下:
    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
  2. stage 并行执行
    对于一些复杂的 hql 可能会需要多个 stage 一起执行来完成,默认情况下,hive 是根据其解析的计划串行执行一个个 stage 的,为了提高执行速度,我们可以开启 stage 并行执行。
    通过 hive.exec.parallel=true开启

stage 是什么? hive 将sql 解析后自动生成的一个抽象概念,比如我们要做饭,那么这个 stage 就可以理解为:1.买菜买米,2.煮饭,3.炒菜,4.上桌。如果开启了并行执行那么,煮饭 和 炒菜 就可以一起执行了,当然前提是你要忙的过来,所以集群资源要足够才行,如果没开启,那么就傻傻的 先煮饭,饭熟了,再炒菜

  1. JVM 重用
    这里JVM 重用是针对 hive 底层的执行引擎 MR 来说的,默认的一个 task 启动一个 jvm 进程来执行。
    通过mapred.job.reuse.jvm.num.tasks=1 可以设置每个JVM 执行的 task 数量

为什么默认值是1 ?
因为如果JVM设置的task数量超过1,那么这个JVM只有等待其执行完自己指定的任务,或者整个 job执行完成才会退出释放资源。
我们可以来假设一下,我们有 6 个task分别是 1,2,3,4,5,6。对应执行的JVM 是 1到6 号,其中 1 需要1min 执行完,其余的都是1s执行完,如果一个jvm执行完一个任务就退出,那么可能在 2s 到 3s 的时候,就只有 1号JVM 占用资源了,而如果不是,2到6号 在 2-3s 执行完毕,但是因为有重用功能,会导致这几个 JVM 继续等待其他任务的派发,直到 1号JVM 执行完毕才会释放 ,导致资源的浪费。
所以才资源不是很充足的情况下,该功能还是要慎用噢~!

  1. 控制 Map 和 Reduce 数量
    可以参考这篇文章

这里啰嗦一下,reduce的数量可能需要根据你自己的业务来设置一下,没什么可说,但是 Map 一般都不会需要自己设置和优化,因为默认一个 Map就是对应 hdfs 上的一个 block,当hdfs block设置合理,并且小文件很少的情况,那么 Map 一般也还算合理并不会有多大影响。

Hive Shell

hive shell 就和 mysql shell 差不多的使用方式,支持 repl 的方式进行数据查询,这里我们主要来说明两个特殊的使用

  • 支持 Hadoop 命令:
    hive shell 是支持 hadoop 的相关操作的,比如:hive> dfs -ls /
  • 支持 Linux 命令:
    hive shell 是支持 Linux 的相关操作的,前面加上!就 ok 了,比如:hive> !ls /

远程调试

通过 hive --debug port=9999 来开启远程调,关于java 远程调试可以参考其他文章

小文件合并

可以参考:https://blog.csdn.net/yycdaizi/article/details/43341239

数据仓库建模

其他小知识点

    原文作者:code_solve
    原文地址: https://www.jianshu.com/p/9fe1559fea30
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞