文章目录
1 Hive 和传统数据库的区别
-
数据更新: 由于 Hive 是针对数仓应用设计的,而数仓的内容是读多写少的,所以,HQL 不支持
INSERT INTO 表 Values()
,UPDATE
,DELETE
操作,仅支持查操作,所有数据在加载时就已经确定,不可更改。而数据库中的数据是经常需要修改的。 -
数据存储位置 :Hive 是建立在 Hadoop 之上的,所有 Hive 的数据都是存储在 HDFS 中的。而数据库可以将数据保存在本地磁盘中。
-
索引:
- Hive 在加载数据的时候不会对数据进行处理,也不会对数据进行扫描,所以 Hive 对索引的支持比较弱。Hive 要访问指定数据时,需要暴力扫描整个数据,因此访问延迟较高。由于 MR 的引入,Hive 可以并行访问数据,所以对于大数据量访问,Hive 仍然具有优势。但 Hive 并不适合少量数据查询,如在线数据查询。
- 数据库中通常会对某些列建立索引,所以对于少量数据查询,数据库效率更高。
2 Hive 内部表和外部表的区别
建表时带有 external 关键字为外部表,否则为内部表。外部表和内部表最主要的区别在于删除表:
- 删除内部表时,HDFS 上的数据和该表在 MySQL 上对应的元数据一块被删除
- 删除外部表时,只删除该表在 MySQL 上对应的元数据,而 HDFS 上的数据不会被删除
选择 :内部表和外部表没有太大区别。如果所有的数据都由 Hive 处理,则可以创建内部表。如果数据的处理由 Hive 和其他工具一块处理,则可以创建外部表。
3 数据倾斜(重点)
3.1 数据倾斜的原因
1. 产生操作
关键词 | 情形 | 后果 |
---|---|---|
大表和小表Join | 大表的 key 集中 | 分发到该 key 对应 Reduce 的数据远高于平均值 |
大表与大表Join,但是空值过多 | 这些空值都由一个 Reduce 处理,非常耗时 | |
group by | group by 维度过小,某个值的数量过多 | 处理某个值的 Reduce 非常耗时 |
count distinct | 某个相同值过多 | 处理该值的 Reduce 非常耗时 |
2. 原因
分布式计算的时候,某些节点的计算能力比较强或者需要计算的数据比较少,早早执行完了,而某些节点计算的能力较差或者由于此节点需要计算的数据比较多,导致出现其他节点的 reduce 阶段任务执行完成,但是这种节点的数据处理任务还没有执行完成。
当我们在执行 HiveQL或者运行 MapReduce 作业时候,如果遇到一直卡在 map100%,reduce99%一般就是遇到了数据倾斜的问题。
3.2 数据倾斜的典型场景及解决方案
1. 大小表 Join
使用 Map Join 让小表(1000条以下的记录)先进内存,在 Map 端完成 Reduce
Map Join 原理:
通常情况下,一个表的数据会分布在不同的 Map 中 进行处理,所以就需要在 Reduce 阶段完成 Join,这就可能导致数据倾斜。
所以 Map Join 会把小表全部读入到内存,在 Map 阶段直接拿另一个表的数据和内存中小表的数据做匹配,由于是在 Map 阶段进行了 Join 操作,所以会提高效率。
2. 大表 Join 大表
如果表中的 null 值太多,null 值的数据会发送到同一个 reduce 端,从而可能会导致内存不够。
方法1:null 值不参与关联
select * from log a join users b on a.user_id is not null and a.user_id = b.user_id
union all
select * from log a where a.user_id is null;
方法2:给空值分配随机的 key 值
select * from log a left outer join users b
on case when a.user_id is null then concat(‘hive’,rand())
else a.user_id end = b.user_id;
一般分配随机 key 的方法更好一些。
3. group by
方法1:开启 Map 端聚合:
开启 Map 端聚合,相当于 Combiner
hive.map.aggr = true
开启负载均衡
hive.groupby.skewindata=true
有数据倾斜的时候进行负载均衡,当设定为 true 时,生成的查询计划会有2个 MR Job。
第一个 MR Job 中,Map 的输出结果会随机分配到 Reduce 中,每个 Reduce 做部分聚合操作,这样处理的结果是相同的 group by key 有可能被分配到不同的 Reduce 中,但减少了 key 的数据量,从而达到负载均衡的目的;
第二个 MR Job 中,根据上一步预处理的数据按照 group by key 分配到对应的 Reduce 中,这个过程可以保证相同的 key 被分配到同一个 Reduce 中,从而完成最终的聚合操作。
方法2:根据业务,合理调整 group by 的维度
4. count(distinct)
方法1:用 count group by 代替
数据量大的时候,count distinct 需要用同一个 Reduce 来完成,就会导致数据倾斜。所以可以先 group by,再用 count
例如:
select a, count(distinct b) from t group by a;
可以改成:
select a, count(1) from (select a, b from t group by a,b) group by a;
方法2:可以将倾斜的数据单独拿出来处理,最后再 union 回去
5. 通用的处理方法
合理设置 Map 数和 Reduce 数