查询时,mapper的结果经过shuffle,按照key的hash来分配到不同的reducer上,如果分配不均匀,导致其中一个或几个reducer的运行时间过长,导致整个mapreducer完成得很慢,这就是数据倾斜。
原因可能是,join、group by、count(distinct )的时候,key的值比较集中,导致这个值的大量数据全放到一个reducer里,如果这个key有大量null值,也导致数据倾斜;
解决方法是:
1. 增大reducer个数
2. 设置负载平衡(会生成两个MR job,先后执行。第一个是随机分配到reducer,可以平衡负载,实现初步的聚合,减少后面的工作量。第二个按照key的hash取mod之后分配到reducer,完成最终的聚合)
3. 小表join大表时,使用mapjoin,可以让小表存入内存,只在map端进行聚合。把小表写在前,大表写在后。
4. 有大量null值时,把null值变成一个字符串加上随机数,反正join时关联不上,不会影响最终结果
5. 需要实现count(distinct )的时候,先对key做group by,然后count(1)即可
注意:对于count(),sum()这种可以由部分结果得到最终结果的聚合函数,方法2、3是有效的,但是对于avg(),mean()这种不能由部分结果得到最终结果的聚合函数,是无效的。
[ 原理 ]
用来限制某些后果不好的查询,它们会消耗大量资源,包括:
1. 如果表使用了分区,但是查询没有用where过滤分区
2. 使用了order by,但是没有加limit限制
3. 笛卡尔乘积,即join不用on而是用where的
1. 使用order by的话,全局排序,所有数据最终在一个reducer里排序,耗时较多,在strict mode下,必须加limit限制,适用于数据量不太大的场景(不清楚加了limit之后是否影响结果???)
2. 使用sort by的话,局部排序,数据分别在各自的reducer排序,不保证最终结果有序
3. distribute by,在map端控制按照哪个字段的hash值分发给各个reducer,通常配合sort by使用,相当于分组排序,distribute by X sort by X相当于全局排序。适用于数据量比较大的排序场景,sort by一定要放在distrubute by后面。例如对于表
type | price | brand |
---|---|---|
noodle | 1600 | huafeng |
bread | 1231 | meixin |
noodle | 1221 | tongyi |
beer | 1432 | zhujiang |
select type, price, brand from store distribute by type sort by type asc, price asc
type相同的会放入同一个reducer,同一个reducer内按照type和price排序,相当于做了分组排序,结果如下
type | price | brand |
---|---|---|
beer | 1432 | zhujiang |
bread | 1231 | meixin |
noodle | 1221 | tongyi |
noodle | 1600 | huafeng |
4.cluster by相当于distribute by X sort by X,但是只能降序排列
属于一种聚合函数,与group by配合使用,可以把组内某个字段所有取值拿出来,作为新的字段。collect_set()、collect_list()作用类同。
1. row_number()返回连续、不重复的排名,key相同时排名也不重复
2. dens_rank()返回连续、重复的排名
3. rank()返回不连续、重复的排名
例如对于:3 3 4 5 5 6
|排名函数|返回排名|
|:|:|
|row_number() |1 2 3 4 5 6 |
|dens_rank() |1 1 2 3 3 4 |
|rank() |1 1 3 4 4 6 |
hive是运行在hadoop之上的一个数据仓库框架,数据放在HDFS上,查询使用MapReduce来执行查询。它支持类似SQL的语言,它其实是个编译器,把SQL编译为MapReduc的作业。
因为基于Hadoop,它拥有hadoop的所有优点和缺点。
优点:
使用类SQL语言,非常方便
使用磁盘而不是内存,所以能处理海量数据,很适合处理大规模的离线数据分析处理。
高容错性,自动备份数据,自动检测并回复故障。
缺点:
数据一词写入多次写出,因此已有的数据表不可更新。
不能做到低延迟
1. 存在内存derby存储,只能开一个客户端,不推荐
2. 存在MySQL数据库,可以多客户端使用,推荐
1. join优化。小表放在join左边,大表放在join右边。因为join在reducer端时,左表会放入内存,所以小表最好放左边
2. 少用order by优化。order by只在一个reducer内排序,太慢了。使用distribute by X sort by X也能达到全局排序。
3. 尽早过滤数据,例如使用分区。
4. 其他参考这篇,写得很好 [ 数据分析利器之hive优化十大原则 ]
由于sql在执行语句的时候,是按照以下顺序执行的:
where->group by->having->select->order by
因为别名是在select里面取的,要在select之后才能被识别,所以where,group by, having都不可以用别名,order by可以用别名。
解决方法:
1. 在where,group by, having用原字段构成的表达式
2. 在在内层加个子查询,把字段名字改了,再在外层用where,group by, having
hive.exec.reducers.bytes.per.reducer(每个reducer最多可接受数据量,默认为1000^3)
hive.exec.reducers.max(集群中最多可以开多少个reducer,默认为999)
但是mapper不宜过多,每个mapper都需要启动的开销,一个mapper启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。