hive优化(一)

来源:互联网 发布:php代替session 编辑:程序博客网 时间:2024/05/17 21:41

要点:

优化时,把 hive sql 当做 map reduce 程序来读,会有意想不到的惊喜。
理解 hadoop 的核心能力,是 hive 优化的根本。
长期观察 hadoop 处理数据的过程,有几个显著的特征:

1.不怕数据多,就怕数据倾斜。2.对 jobs 数比较多的作业运行效率相对比较低,比如即使有几百行的表,如果多次关联多次汇总,产生十几个 jobs,没半小时是跑不完的。map reduce 作业初始化的时间是比较长的。3.对 sum,count 来说,不存在数据倾斜问题。4.对 count(distinct ),效率较低,数据量一多,准出问题,如果是多 count(distinct )效率更低。

优化可以从几个方面着手:

1. 好的模型设计事半功倍。2. 解决数据倾斜问题。3. 减少 job 数。4. 设置合理的 map reduce 的 task 数,能有效提升性能。(比如,10w+级别的计算,用160 个 reduce,那是相当的浪费,1 个足够)。5. 自己动手写 sql 解决数据倾斜问题是个不错的选择。set hive.groupby.skewindata=true;这是通用的算法优化,但算法优化总是漠视业务,习惯性提供通用的解决方法。 Etl 开发人员更了解业务,更了解数据,所以通过业务逻辑解决倾斜的方法往往更精确,更有效。6. 对 count(distinct)采取漠视的方法,尤其数据大的时候很容易产生倾斜问题,不抱侥幸心理。自己动手,丰衣足食。7. 对小文件进行合并,是行至有效的提高调度效率的方法,假如我们的作业设置合理的文件数,对云梯的整体调度效率也会产生积极的影响。8. 优化时把握整体,单个作业最优不如整体最优。

优化案例:

问题 1:如日志中,常会有信息丢失的问题,比如全网日志中的 user_id,如果取其中的
user_id 和 bmw_users 关联,就会碰到数据倾斜的问题。

解决方法 1. User_id 为空的不参与关联,例如:Select *From log aJoin bmw_users bOn a.user_id is not nullAnd a.user_id = b.user_idUnion allSelect *from log awhere a.user_id is null.解决方法 2 :Select *from log aleft outer join bmw_users bon case when a.user_id is null then concat(‘dp_hive’,rand() ) else a.user_id end = b.user_id;总结:2 比 1 效率更好,不但 io 少了,而且作业数也少了。1 方法 log 读取两次,jobs 是2。2 方法 job 数是 1 。这个优化适合无效 id(比如-99,’’,null 等)产生的倾斜问题。把空值的 key 变成一个字符串加上随机数,就能把倾斜的数据分到不同的 reduce 上 ,解决数据倾斜问题。因为空值不参与关联,即使分到不同的 reduce 上,也不影响最终的结果。附上hadoop 通用关联的实现方法(关联通过二次排序实现的,关联的列为 parition key,关联的列 c1 和表的 tag 组成排序的 group key,根据 parition key 分配 reduce。同一 reduce 内根据 group key 排序)。

问题 2:不同数据类型 id 的关联会产生数据倾斜问题。

一张表 s8 的日志,每个商品一条记录,要和商品表关联。但关联却碰到倾斜的问题。s8的日志中有字符串商品 id,也有数字的商品 id,类型是 string 的,但商品中的数字 id 是 bigint的。猜测问题的原因是把 s8 的商品 id 转成数字 id 做 hash 来分配 reduce,所以字符串 id的 s8 日志,都到一个 reduce 上了,解决的方法验证了这个猜测。方法:把数字类型转换成字符串类型Select * from s8_log aLeft outer join r_auction_auctions bOn a.auction_id = cast(b.auction_id as string);

问题 3:利用 hive 对 UNION ALL 的优化的特性
hive 对 union all 优化只局限于非嵌套查询。

比如以下的例子:select * from(select * from t1Group by c1,c2,c3Union allSelect * from t2Group by c1,c2,c3) t3Group by c1,c2,c3;从业务逻辑上说,子查询内的 group by 怎么都看显得多余(功能上的多余,除非有count(distinct)),如果不是因为 hive bug 或者性能上的考量(曾经出现如果不子查询group by ,数据得不到正确的结果的 hive bug)。所以这个 hive 按经验转换成select * from(select * from t1Union allSelect * from t2) t3Group by c1,c2,c3;经过测试,并未出现 union all 的 hive bug,数据是一致的。mr 的作业数有 3 减少到 1。t1 相当于一个目录,t2 相当于一个目录,那么对 map reduce 程序来说,t1,t2 可以做为map reduce 作业的 mutli inputs。那么,这可以通过一个 map reduce 来解决这个问题。Hadoop 的计算框架,不怕数据多,就怕作业数多。但如果换成是其他计算平台如 oracle,那就不一定了,因为把大的输入拆成两个输入,分别排序汇总后 merge(假如两个子排序是并行的话),是有可能性能更优的(比如希尔排序比冒泡排序的性能更优)。

问题 4:比如推广效果表要和商品表关联,效果表中的 auction id 列既有商品 id,也有数
字 id,和商品表关联得到商品的信息。那么以下的 hive sql 性能会比较好

Select * from effect aJoin (select auction_id as auction_id from auctionsUnion allSelect auction_string_id as auction_id from auctions) bOn a.auction_id = b.auction_id。比分别过滤数字 id,字符串 id 然后分别和商品表关联性能要好。这样写的好处,1 个 MR 作业,商品表只读取一次,推广效果表只读取一次。把这个 sql 换成MR 代码的话,map 的时候,把 a 表的记录打上标签 a,商品表记录每读取一条,打上标签b,变成两个<key ,value>对,<b,数字 id>,<b,字符串 id>。所以商品表的 hdfs 读只会是一次。

问题 5:先 join 生成临时表,在 union all 还是写嵌套查询,这是个问题。比如以下例
子:

Select *From (select *From t1Uion allselect *From t4Union allSelect *From t2Join t3On t2.id = t3.id) xGroup by c1,c2;这个会有 4 个 jobs。假如先 join 生成临时表的话 t5,然后 union all,会变成 2 个 jobs。Insert overwrite table t5Select *From t2Join t3On t2.id = t3.id;Select * from (t1 union all t4 union all t5) ;hive 在 union all 优化上可以做得更智能(把子查询当做临时表),这样可以减少开发人员的负担。出现这个问题的原因应该是 union all 目前的优化只局限于非嵌套查询。如果写 MR 程序这一点也不是问题,就是 multi inputs。
原创粉丝点击