Hive的高级应用-视图-优化

视图

1,功能:

和关系型数据库一样,Hive 中也提供了视图的功能,享用基本表的数据,不会生成另外一份数据。

2, 和关系型数据库中的区别:

  • (1)只有逻辑视图,暂不支持物化视图(后续将在1.0.3版本以后支持);
    • 逻辑视图:不存储任何数据,只有定义,在查询中是转换为对应的定义的HQL去查询。
    • 物化视图:将数据转换为一个表,实际存储着数据,这样查询数据,就不用关联一大堆表,如果表很大的话,会在临时表空间内做大量的操作。
  • (2)视图只能查询,不能LOAD/INSERT/UPDATE/DELETE 数据;
  • (3)视图在创建时候,只是保存了一份元数据,当查询视图的时候,才开始执行视图对应的那些子查询。

3, 操作

  • 1,创建视图

      CREATE VIEW student_view 
    

AS SELECT * FROM student where score>85 LIMIT 10;
CREATE VIEW IF NOT EXISTS student_view (address COMMENT ‘address’)
COMMENT ‘view student’
AS SELECT address FROM student;

  • 2,查看视图
    查看视图列表:SHOW TABLES;
    查看视图详情:DESC student_view;

  • 3,删除视图

      DROP VIEW student_view;
    

数据倾斜

1,什么是数据倾斜?

由于数据分布不均匀,造成数据大量集中到一点,造成数据热点。
数据倾斜其实是进行分布式计算的时候,某些节点的计算能力比较强或者需要计算的数据比较少,早早执行完了,某些节点计算的能力较差或者由于此节点需要计算的数据比较多,导致出现其他节点的reduce阶段任务执行完成,但是这种节点的数据处理任务还没有执行完成。

2,数据倾斜主要表现

(1)当我们在执行HiveQL或者运行MapReduce作业时候,如果遇到一直卡在map100%,reduce99%一般就是遇到了数据倾斜的问题。查看任务监控页面,发现只有少量(1个或者几个) reduce 子任务未完成, 因为其处理的数据量和其他的 reduce 差异过大。
(2)单一 reduce 处理的记录数和平均记录数相差太大,通常达到 3 倍甚至更多,最长时间远大于平均时长。

3,Hadoop 框架的特性

  • (1)不怕数据大,怕数据倾斜;
  • (2)Jobs 数比较多的作业运行效率相对比较低,如子查询较多;
  • (3)SUM,COUNT,MAX,MIN 等聚集函数,不会有数据倾斜问题。

4,容易数据倾斜情况

  • (1)小表关联超大表 JOIN;
  • (2)GROUP BY 不和聚集函数搭配使用的时候;
  • (3)COUNT(DISTINCT),在数据量大的情况下,容易数据倾斜,因为 COUNT(DISTINCT) 是按 GROUP BY字段分组,按 DISTINCT 字段排序。
    总体概要
    在这里插入图片描述

5,产生数据倾斜的具体原因

  • (1)key 分布不均匀,少量的 key 对应大量 value
  • (2)业务数据本身的特性
  • (3)建表考虑不周全
  • (4)某些 HQL 语句本身就存在数据倾斜

6,业务场景

  • 1,空值产生的数据倾斜

    • 场景说明
      在日志中,常会有信息丢失的问题, 比如日志中的 user_id,如果取其中的 user_id 和用户表中的 user_id 相关联,就会碰到数据倾斜的问题。

    • 解决方案
      方案一: user_id 为空的不参与关联

        SELECT * FROM log a 
        JOIN user b 
        ON a.user_id IS NOT NULL 
        AND a.user_id = b.user_id 
        UNION ALL
        SELECT * FROM log c WHERE c.user_id IS NULL;
      

      方案二: 赋予空值新的 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;
      

      方案二比方案一效率高,job数少,方案一2个job,方案二只需1个job

  • 2,不同数据类型关联产生数据倾斜

    • 场景说明
      用户表中 user_id 字段为 int, log 表中 user_id 为既有 string 也有 int 的类型。当按照两个表的 user_id 进行 Join 操作的时候,默认的 hash 操作会按照 int 类型的 id 来进行分配, 这样就会导致所有的 string 类型的 id 就被分到同一个 reducer 当中。

    • 解决方案
      把 int 类型 id 转换成 string 类型的 id

        SELECT * FROM user a 
        LEFT OUTER JOIN log b 
        ON b.user_id = CAST(a.user_id AS STRING);
      
  • 3,大小表关联查询

    • 解决方案
      MapJoin 概念:将其中的某个表(全量数据)分发到所有 Map 端进行 Join,从而避免了reduce,前提要求是内存足以装下该全量数据。

        SELECT /*+ MAPJOIN(user) */ 
        user.user_id, log.user_id
        FROM user JOIN log 
        WHERE user.user_id=log.user_id;
      
    • (2)示例详解
      以大表 a 和小表 b 为例,所有的 MapTask 节点都装载小表 b 的所有数据,然后大表 a 的一个数据块,数据比如说是 a1, 去跟 b 全量数据做连接, 就省去了 reduce 来做汇总的过程。

    • (3)使用条件
      内存允许的条件下
      只限于做 Join 查询的时候

    • (4)特殊情况
      大大表关联
      把大表切分成小表,然后分别 MapJoin

Hive 执行过程实例分析

JOIN

1,示例

  • 内连接:

      SELECT u.name, o.orderid FROM order o
      JOIN user u 
      ON o.uid = u.uid;
    

2,实现过程

  • (1)Map Join(Map 阶段完成 Join)
    如果不指定 MapJoin 或者不符合 MapJoin 的条件,那么 Hive 解析器会将 Join 操作转换成 Common Join,即:在 Reduce 阶段完成 Join。
  • (2)Common Join(Reduce 阶段完成 Join)
    具体实现过程
    在这里插入图片描述
    • 1,Map阶段
      (1)读取源表数据,Map 输出以 JOIN ON 条件中的列作为 Key,若有多个列,则 Key 是这些列的组合
      (2)Map 输出以 JOIN 之后所关心的列(SELECT 或者 WHERE 中需要用到的)作为 Value,当有多个列时, Value 是这些列的组合。在 Value 中还会包含表的 Tag 信息,用于标明此 Value 对应于哪个表
      (3)按照 Key 进行排序
    • 2,Shuffle阶段
      根据 Key 的值进行 Hash,并将 Key/Value 对按照 Hash 值推送至不同的 Reduce 中,这样确保两个表中相同的 Key 位于同一个 Reduce 中
    • 3,Reduce阶段
      根据 Key 值进行 Join 操作,并且通过 Tag 来识别不同表中的数据

GROUP BY

示例

	SELECT rank, isonline, count(*) FROM city 

GROUP BY rank, isonline;

实现过程

  • 具体实现过程
    在这里插入图片描述
  • 1,Map阶段
    (1)Map 输出以 GROUP BY 的字段组合作为 Key,如果有多个列,则 Key 是这些列的组合;
    (2)Map 输出以 Key 出现次数之和作为 Value;
    (3)按照 Key 进行排序。
  • 2,Shuffle阶段
    根据 Key 的值进行 Hash,并将 Key/Value 对按照 Hash 值推送至不同的 Reduce 中,这样确保两个表中相同的 Key 位于同一个 Reduce 中。
  • 3,Reduce阶段
    Reducer 根据 Key 值对 Value 进行叠加。

4,Hive 优化策略

Hadoop 框架计算特性

  • 1,不怕数据量大,怕数据倾斜
  • 2,job 数越多作业运行效率越低
    原因:MapReduce 作业初始化的时间比较长
  • 3,SUM,COUNT,MAX,MIN 等 UDAF,不怕数据倾斜
    原因:Map 端的汇总合并优化,使数据倾斜不成问题
    4 ,COUNT(DISTINCT userid),在数据量大的情况下,效率较低
    原因:COUNT(DISTINCT)是按 GROUP BY 字段分组,按 DISTINCT 字段排序,一般这种分布方式很容易数据倾斜

常用优化手段

  • 1,好的模型设计事半功倍
  • 2,解决数据倾斜问题
  • 3,减少 job 数
  • 4,设置合理的 MapReduce 的 task 数,能有效提升性能
  • 5,可以使用通用的算法优化手段:set hive.groupby.skewindata=true;
    若是不适应特定业务背景时,可以通过业务逻辑精确有效的解决数据倾斜问题
  • 6,数据量较大的情况下,慎用 COUNT(DISTINCT), GROUP BY 容易产生倾斜问题
  • 7,对小文件进行合并,是行之有效的提高调度效率的方法
  • 8,优化时把握整体,单个作业最优不如整体最优

全排序

  • 1,CLUSTER BY: 对同一字段分桶并排序,CLUSTER BY = DISTRIBUTE BY + SORT BY。
  • 2,DISTRIBUTE BY: 分桶,保证同一字段值只存在一个结果(reducer)当中。
  • 3,SORT BY: 局部排序,单个 Reduce 结果。
  • 4,ORDER BY: 全局排序。

笛卡尔积

  • Hive 设定为严格模式(hive.mapred.mode=strict,默认是nonstrict)时,不允许在 HQL 语句中出现笛卡尔积。说明了 Hive 对笛卡尔积支持较弱
  • 经常是一个大表和一个小表进行 Join,结果仍然很大(以至于无法用单机处理)
    • 解决方法: MapJoin
  • MapJoin详解
    • 解释
      会在 Map 端完成 Join 操作,需要将 Join 操作的一个或多个表完全读入内存

    • MapJoin 具体用法
      1,代码:

        SELECT /* +mapjoin(a) */ a.id , name, age FROM a JOIN b ON a.id = b.id;
      

      在查询/子查询的 SELECT 关键字后面添加/*+ MAPJOIN(TABLELIST) */提示优化器转化为 MapJoin;
      其中 tablelist 可以是一个表,或以逗号连接的表的列表,tablelist 中的表将会读入内存,应该将小表写在这里
      2,参数控制

        hive.auto.convert.join=true     ##默认 MapJoin 优化自动开启														
        hive.mapjoin.smalltable.filesize=25000000   ##设置小表不超过多大时自动开启 MapJoin 优化
      
    3,解决问题
    有一个极小的表<1000行(a是小表);
    需要做不等值 Join 操作(a.x<b.y或者a.x like b.y等)。普通 Join 语法不支持不等于操作,Hive 语法解析会直接抛出错误。
    4,出现问题
    在子查询中可能出现未知 bug
    解决方法:在大表和小表做笛卡尔积时,可以给 Join 添加一个 Join key

IN/EXISTS 语句

推荐使用 Hive 的一个高效替代方案: LEFT SEMI JOIN

GROUP BY

  • Map 端部分聚合
    并不是所有的聚合操作都需要在 Reduce 端完成,很多聚合操作都可以先在 Map 端进行部分聚合,最后在 Reduce 端得出最终结果。

  • MapReduce 的 combiner 组件

      hive.map.aggr = true    ##是否在 Map 端进行聚合,默认为 true
      hive.groupby.mapaggr.checkinterval = 100000    ##在 Map 端进行聚合操作的条目数目
    

小文件合并

  • 问题
    文件数目过多,会给 HDFS 带来压力,并且会影响处理效率,可以通过合并 Map 和 Reduce 的结果文件

  • 参数设置

      hive.merge.mapfiles = true                  ##是否和并 Map 输出文件,默认为 true
      hive.merge.mapredfiles = false              ##是否合并 Reduce 输出文件,默认为 false
      hive.merge.size.per.task = 256*1000*1000    ##合并文件的大小
    

猜你喜欢

转载自blog.csdn.net/theone_1/article/details/84111279