视图
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 类型的 idSELECT * 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 来识别不同表中的数据
- 1,Map阶段
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 优化
有一个极小的表<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 ##合并文件的大小