zoukankan      html  css  js  c++  java
  • Hive优化案例

    1.Hadoop计算框架的特点

    • 数据量大不是问题,数据倾斜是个问题。
    • jobs数比较多的作业效率相对比较低,比如即使有几百万的表,如果多次关联多次汇总,产生十几个jobs,耗时很长。原因是map reduce作业初始化的时间是比较长的。
    • sum,count,max,min等UDAF,不怕数据倾斜问题,hadoop在map端的汇总并优化,使数据倾斜不成问题。
    • count(distinct),在数据量大的情况下,效率较低,如果是多count(distinct)效率更低,因为count(distinct)是按group by字段分组,按distinct字段排序,一般这种分布式是很倾斜的,比如男uv,女uv,淘宝一天30亿的pv,如果按性别分组,分配2个reduce,每个reduce处理15亿数据。

    2.优化的常用手段

    •  好的模型设计事半功倍。
    • 解决数据倾斜问题。
    • 减少job数。
    • 设置合理的map reduce的task数,能有效提升性能。(比如,10w+级别的计算,用160个reduce,那是相当的浪费,1个足够)。
    • 了解数据分布,自己动手解决数据倾斜问题是个不错的选择。set hive.groupby.skewindata=true;这是通用的算法优化,但算法优化有时不能适应特定业务背景,开发人员了解业务,了解数据,可以通过业务逻辑精确有效的解决数据倾斜问题。
    • 数据量较大的情况下,慎用count(distinct),count(distinct)容易产生倾斜问题。
    • 对小文件进行合并,是行至有效的提高调度效率的方法,假如所有的作业设置合理的文件数,对云梯的整体调度效率也会产生积极的正向影响。
    • 优化时把握整体,单个作业最优不如整体最优

    3.优化案例

    3.1 使用 SQL 技巧写出高效率的查询

    场景: 有一张user表,为卖家每天收入表,user_id,ds(日期)为key,属性有主营类目,指标有交易金额,交易笔数。每天要取前10天的总收入,总笔数,和最近一天的主营类目

    常规方法:

    1.利用分析函数,取每个user_id最近一天的主营类目,存入临时表t1

    2.汇总10天的总交易金额,交易比数,存入临时表t2

    3.关联t1,t2,得到最终的结果

    解决方法2:

    select user_id,
      substr(max(concat(ds,cat)),9) as main_cat,
      sum(qty),
      sum(amt)
    from users
    where ds between 20101201 and 20101210
    group by user_id;
    

    解决方法2的开销等于常规方法的第二步的开销,整体性能提升2倍。这种方式在RAC上也适用。

    3.2 空值产生的数据倾斜

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

    解决方法1: user_id为空的不参与关联

    select * from log a
      join bmw_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 bmw_users b
      on 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上 ,解决数据倾斜问题。附上hadoop通用关联的实现方法(关联通过二次排序实现的,关联的列为parition key,关联的列 c1 和表的 tag 组成排序的 group key ,根据 parition key 分配 reduce 。同一 reduce 内根据 group key 排序)

    3.3 不同数据类型关联产生数据倾斜

    场景:一张表 s8_log,每个商品一条记录,要和商品表关联。但关联却碰到倾斜的问题。s8_log 中有字符串商品 id,也有数字的商品 id。字符串商品 id 类型是 string 的,但商品中的数字 id 是 bigint 的。问题的原因是把 s8_log 的商品 id 转成数字 id 做 Hash(数字的 Hash 值为其本身,相同的字符串的 Hash 也不同)来分配 Reducer,所以相同字符串 id 的 s8_log,都到一个 Reducer 上了。

    解决方法:把数字类型转换成字符串类型

    select * from s8_log a
      left outer join r_auction_auctions b
      on a.auction_id = cast(b.auction_id as string);
    

    3.4 利用 Hive 对 union all 优化的特性

    多表 union all 会优化成一个 job。比如推广效果表要和商品表关联,效果表中的 auction id 列既有商品 id,也有数字 id,和商品表关联得到商品的信息。

    以下的hive sql性能会比较好

    select * from effect a
    join (
      select auction_id as auction_id from auctions
      union all
      select auction_string_id as auction_id from auctions
    ) b
    on a.auction_id = b.auction_id;
    

    结论:比分别过滤数字 id,字符串 id 然后分别和商品表关联性能要好。 这样写的好处,1个 MR 作业,商品表只读取一次,推广效果表只读取一次。把这个 sql 换成 MR 代码的话,map 的时候,把 a 表的记录打上标签 a ,商品表记录每读取一条,打上标签 t,变成两个<key,value> 对,<t,数字id,value>,<t,字符串id,value>。所以商品表的 HDFS 读只会是一次。

    3.5 解决 Hive 对 union all 优化的短板

    hive 对UNION ALL的优化的特性:对union all优化只局限于非嵌套查询

    3.5.1 消灭子查询内的 group by

    对于如下 SQL:

    select * from (
      select * from t1
        group by c1,c2,c3
      union all 
      select * from t2
        group by c1,c2,c3) t3
    group by c1,c2,c3;
    

    存在的问题:从业务逻辑上说,子查询内的 group by 功能与外层的 group by 重复,除非子查询内有 count(distinct)。 调整后的sql:

    select * from (
      select * from t1
      union all
      select * from t2) t3
    group by c1,c2,c3;
    

    结论:经过测试,并未出现 union all 的 hive bug,数据是一致的。MR 的作业数由3减少到1。 t1 相当于一个目录,t2 相当于一个目录,对map reduce程序来说,t1,t2 可以做为 map reduce 作业的 mutli inputs。这可以通过一个 map reduce 来解决这个问题。Hadoop的计算框架,不怕数据多,怕作业数多

    3.5.2 消灭子查询内的count(distinct),max,min

    select * from (select * from t1
      group by c1,c2,c3
      union all 
    select c1,c2,c3,count(disintct c4) from t2
      group by c1,c2,c3) t3
      group by c1,c2,c3;
    

    由于子查询里头有count(distinct )操作,直接去group by将达不到业务目标。这时采用临时表消灭count(distinct)作业不但能解决倾斜问题,还能有效减少jobs。
    如以下例子:

    insert t4 select c1,c2,c3,c4 from t2 group by c1,c2,c3;
    select c1,
          c2,
          c3,
          sum(income),
          sum(uv)
    from (select c1,c2,c3,income,0 as uv from t1
         union all
         select c1,c2,c3,0 as income,1 as uv from t2) t3 group by c1,c2,c3;
    

    Job数是2,减少一半,而且两次mr比count(distinct)效率更高。

    3.5.3 消灭子查询内的join

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

    select * from (
      select * from t1
      union all
      select * from t4
      union all
      select * from t2
        join t3 on t2.id = t3.id) x
    group by c1,c2;
    

    这个会有 4 个 jobs。假如先 join 生成临时表的话 t5,然后 union all,会变成 2 个 jobs。

    insert overwrite table t5
    select *
      from t2
      join t3
      on t2.id = t3.id;
    select * from (t1 union all t4 union all t5);
    

    结论: Hive 在 union all 优化上可以做得更智能(把子查询当做临时表),这样可以减少开发人员的负担。如果写MR程序这不是问题,就是 multi inputs。

    3.5.5 小表不小不大,怎么用 map join 解决倾斜问题

    使用 map join 解决小表(记录数少)关联大表的数据倾斜问题,这个方法使用的频率非常高,但如果小表很大,大到map join会出现bug或异常,这时就需要特别的处理。云瑞和玉玑提供了非常给力的解决方案。 以下例子:

    select * from log a
      left outer join members b
      on a.memberid = b.memberid;
    

    members 表有 600w+ 的记录,把 members 分发到所有的 map 上也是个不小的开销,而且 map join 不支持这么大的小表。如果用普通的 join,又会碰到数据倾斜的问题。

    解决方法:

    select /*+mapjoin(x)*/* from log a
      left outer join (
        select  /*+mapjoin(c)*/d.*
          from ( select distinct memberid from log ) c
          join members d
          on c.memberid = d.memberid
        ) x
      on a.memberid = b.memberid;
    

    假如,log里memberid有上百万个,这就又回到原来map join问题。所幸,每日的会员uv不会太多,有交易的会员不会太多,有点击的会员不会太多,有佣金的会员不会太多等等。所以这个方法能解决很多场景下的数据倾斜问题。

    3.6 较通用的数据倾斜解决方法

    HIVE下通用的数据倾斜解决方法,double被关联的相对较小的表,这个方法在mr的程序里常用。
    Select * from log a
    Left outer join (select /*+mapjoin(e)*/
    memberid, number
      From members d
      Join num e
      ) b
    On a.memberid= b.memberid
    And mod(a.pvtime,30)+1=b.number;
    Num表只有一列number,有30行,是1,30的自然数序列。把member表膨胀成N份(基于倾斜程度做一个合适的选择),然后把log数据根据memberid和pvtime分到不同的reduce里去,这样可以保证每个reduce分配到的数据可以相对均匀。就目前测试来看,使用mapjoin先过滤的方案性能稍好。后面的方案适合在map join无法解决问题的情况下。

    设想,把如下的优化方案做成通用的hive优化方法

    1. 采样log表,哪些memberid比较倾斜,得到一个结果表tmp1。由于对计算框架来说,所有的数据过来,他都是不知道数据分布情况的,所以采样是并不可少的。Stage1
    2. 数据的分布符合社会学统计规则,贫富不均。倾斜的key不会太多,就像一个社会的富人不多,奇特的人不多一样。所以tmp1记录数会很少。把tmp1和members做map join生成tmp2,把tmp2读到distribute file cache。这是一个map过程。Stage2
    3. map读入members和log,假如记录来自log,则检查memberid是否在tmp2里,如果是,输出到本地文件a,否则生成<memberid,value>的key,value对,假如记录来自member,生成<memberid,value>的key,value对,进入reduce阶段。Stage3
    4. 最终把a文件,把Stage3 reduce阶段输出的文件合并起写到hdfs。

    这个方法在hadoop里应该是能实现的。Stage2是一个map过程,可以和stage3的map过程可以合并成一个map过程。 这个方案目标就是:倾斜的数据用mapjoin,不倾斜的数据用普通的join,最终合并得到完整的结果。用hive sql写的话,sql会变得很多段,而且log表会有多次读。倾斜的key始终是很少的,这个在绝大部分的业务背景下适用。那是否可以作为hive针对数据倾斜join时候的通用算法呢?

    3.7 多粒度uv的改进

    场景:比如要计算店铺的uv,还有要计算页面的uv,pvip。
    方案一:
    insert overwrite table shop_uv
    Select shopid,count(distinct uid)
    From log group by shopid;

    insert overwrite table page_uv
    Select pageid, count(distinct uid),
    From log group by pageid;

    由于存在数据倾斜问题,这个结果的运行时间是非常长的。
    方案二:
    From log
    Insert overwrite table t1 (type='1')
    Select shopid as dim
    Group by shopid ,acookie
    Insert overwrite table t1 (type='2')
    select pageid as dim Group by pageid,acookie;

    店铺uv:
    insert overwrite table shop_uv Select dim,sum(1)
    From t1
    Where type ='1'
    Group by dim ;

    页面uv:
    insert overwrite table page_uv Select dim,sum(1)
    From t1
    Where type ='2'
    Group by dim ;
    这里使用了multi insert的方法,有效减少了hdfs读,但multi insert会增加hdfs写,多一次额外的map阶段的hdfs写。使用这个方法,可以顺利的产出结果。缺点是 存在重复IO,并且作业数据较多。
    方案三:
    Insert into t1
    Select type,type_name
    From (
    Select 'page' as type,
      Pageid as type_name,
      Uid
    From log
    Union all
    Select 'shop' as type,
      Shopid as type_name,
      Uid
    From log ) y
    Group by type,type_name,uid;

    汇总得到page和店铺uv
    Insert into t2
    Select type,type_name,sum(1)
    From t1
    Group by type,type_name;

    分出page和店铺的uv
    From t2
    Insert into t3
    Select type,type_name,uv
    Where type='page'
    Select type,type_name,uv
    Where type='shop';

    比较: 最终得到两个结果表t3,页面uv表,t4,店铺结果表。从io上来说,log一次读。但比方案2少次hdfs写(multi insert有时会增加额外的map阶段hdfs写)。作业数减少1个到3,有reduce的作业数由4减少到2,第三步是一个小表的map过程,分下表,计算资源消耗少。但方案2每步都是大规模的去重汇总计算。
    这个优化的主要思路是,map reduce作业初始化的时间比较长,既然起来了,让他多干点活,顺便把页面按uid去重的活也干了,省下log的一次读和作业的初始化时间,但增加了本地磁盘读写。效率提升较多。 这个方案适合平级的不需要逐级向上汇总的多粒度uv计算,粒度越多,比较节省资源,比较通用。如果说,把两个uv分成两个脚本,分别并行计算,那就不敢保证这个方案比分脚本的方案快了,但这个更省资源。

    3.8 多粒度,逐层向上汇总的uv计算

    场景:
    比如4个维度,a,b,c,d,分别计算a,b,c,d,uv;a,b,c,uv;a,b,uv;a;uv,total uv4个结果表。这可以用多粒度uv计算的方法,这里由于uv场景的特殊性,多粒度,逐层向上汇总,就可以使用一次排序,所有uv计算受益的计算方法。 目前mm_log日志一天有25亿+的pv数,要从mm日志中计算uv,与ipuv,一共计算五个层次的结果表

    1. (memberid,siteid,adzoneid,province,uv,ipuv) R_TABLE_4
    2. (memberid,siteid,adzoneid,uv,ipuv) R_TABLE_3
    3. (memberid,siteid,uv,ipuv) R_TABLE_2
    4. (memberid,uv,ipuv) R_TABLE_1
    5. (uv,ipuv) R_TABLE

    第一步:
    按memberid,siteid,adzoneid,province,使用group去重,产生临时表,对cookie,ip 打上标签放一起,一起去重,临时表叫T_4;
    Select memberid,siteid,adzoneid,province,type,user
    From(
    Select memberid,siteid,adzoneid,province,'a' type ,cookie as user from mm_log where ds=20101205
    Union all
    Select memberid,siteid,adzoneid,province,'i' type ,ip as user from mm_log where ds=20101205
    ) x group by memberid,siteid,adzoneid,province,type,user ;
    第二步:
    排名,产生表T_4_NUM.Hadoop最强大和核心能力就是parition 和 sort.按type,acookie分组, Type,acookie,memberid,siteid,adzoneid,province排名。
    Select * ,
    row_number(type,user,memberid,siteid,adzoneid ) as adzone_num ,
    row_number(type,user,memberid,siteid ) as site_num,
    row_number(type,user,memberid ) as member_num,
    row_number(type,user ) as total_num
    from (select * from T_4 distribute by type,user sort by type,user, memberid,siteid,adzoneid ) x;
    这样就可以得到不同层次粒度上user的排名,相同的user id在不同的粒度层次上,排名等于1的记录只有1条。取排名等于1的做sum,效果相当于Group by user去重后做sum操作。
    第三步:
    不同粒度uv统计,先从最细粒度的开始统计,产生结果表R_TABLE_4,这时,结果集只有10w的级别。
    如统计memberid,siteid,adzoneid,provinceid粒度的uv使用的方法就是
    Select memberid,siteid,adzoneid, provinceid,
    sum(case when type ='a' then cast(1) as bigint end ) as province_uv ,
    sum(case when type ='i' then cast(1) as bigint end ) as province_ip ,
    sum(case when adzone_num =1 and type ='a' then cast(1) as bigint end ) as adzone_uv ,
    sum(case when adzone_num =1 and type ='i' then cast(1) as bigint end ) as adzone_ip ,
    sum(case when site_num =1 and type ='a' then cast(1) as bigint end ) as site_uv ,
    sum(case when site_num =1 and type ='i' then cast(1) as bigint end ) as site_ip ,
    sum(case when member_num =1 and type ='a' then cast(1) as bigint end ) as member_uv ,
    sum(case when member_num =1 and type ='i' then cast(1) as bigint end ) as member_ip ,
    sum(case when total_num =1 and type ='a' then cast(1) as bigint end ) as total_uv ,
    sum(case when total_num =1 and type ='i' then cast(1) as bigint end ) as total_ip ,
    from T_4_NUM
    group by memberid,siteid,adzoneid, provinceid ;
    广告位粒度的uv的话,从R_TABLE_4统计,这是做10w级别记录数的统计
    Select memberid,siteid,adzoneid,sum(adzone_uv),sum(adzone_ip)
    From R_TABLE_4
    Group by memberid,siteid,adzoneid;
    memberid,siteid的uv计算 ,
    memberid的uv计算,
    total uv 的计算也都从R_TABLE_4汇总。

    3.9 一次扫描得到多个结果

    场景:
    经常遇到几个结果表都是出自一个源表,但是要取的字段不一样。
    比如,需要从处罚表得到当天处罚的记录明细,和被处罚的会员的累积处罚积分。
    如果采用通常的做法,得到明细数据查询一次处罚表,得到汇总数据再查一次处罚表,这样需要扫两次,当表很大的时候这个代价会非常大。 用multi_select可以扫描一次就得到这两个结果。

    代码如下: set hive.merge.mapfiles = false;
    from(select * from s_bmw_punish_award_result where pt='$env.lastPartition' and be_punished_type = 0) a
    insert overwrite table m_mid_punish_result
    partition (pt='$env.lastPartition',child='01')
    select
    '$formatDate' as gmt_create,
    id,
    punish_award_rule_id,
    be_punished_type,
    from_id,
    substr(create_date,1,10) as create_date,
    point_range,
    case when status=2 then substr(gmt_modified,1,10) end as cancel_date,
    status,
    be_punished_id,
    operator
    where dateCompare(create_date ,'$env.date',0)=0
    insert overwrite table m_mid_punish_result
    partition (pt='$env.lastPartition',child='02')
    select
    '$formatDate' as gmt_create,
    id,
    punish_award_rule_id,
    be_punished_type,
    from_id,
    substr(create_date,1,10) as create_date,
    point_range,
    substr(gmt_modified,1,10)as cancel_date,
    status,
    be_punished_id,
    operator
    where dateCompare(gmt_modified,'$env.date',0)=0
      and status=2
      and dateCompare(create_date,'$env.date',0)<>0
    insert overwrite table m_mid_punish_result_3
    partition (pt='$env.lastPartition')
    select be_punished_id,
    sum(case when point_is_effect = 1 then abs(cast(point as double )) else 0.00 end ) as sum_point
    where dateCompare(create_date,'20090915',0)>=0
    and dateCompare(create_date,'$env.date',1)<0
    group by be_punished_id



     3.10 where条件很简单,但是太多

    insert overwrite table t_afan_auc_prop3
    partition(pt='20120717000000')
    select auction_id,property_id,value_id 
    from r_auctions_properties 
    where pt='20120717000000' 
    and 
    (
    (property_id = 1626130 and value_id = 46276) or
    (property_id = 33510 and value_id = 31533293) or
    (property_id = 33510 and value_id = 119834) or
    (property_id = 33510 and value_id = 119831) or
    (property_id = 33448 and value_id = 118432) or
    (property_id = 33448 and value_id = 21039) or
     xxxx
    )
    

    and 里面的or 条件有170多个
    这个分区有80G的数据,120亿条数据,单独扫描只需要不到5分钟,但是运行这个sql确需要1个多小时,主要原因是因为这个and条件hive在生成执行计划时产生了一个嵌套层次很多的算子。
    property_id 和 value_id 都是string 类型的字段
    解决方案:
    (1)property_id、value_id 的值对搞成一个小表,然后通过一次mapjoin
    (2)写个udf,把这些预设值读取进去,udf来完成这个and数据过滤操作

    3.11 hive tips

    3.11.1 map only的作业

    有些简单的sql语句,没有reduce产生,输入数据很大,有很多map,每个map都会有结果文件产生,输出文件数会很大。

     (1)容易导致quota超
     (2)会运行merge job,这个merge job用来合并小文件。
    

    merge job有两种实现:

     (1)hive.mergejob.maponly为true,使用只有map的MR job来合并小文件,使用了org.apache.hadoop.hive.ql.io.CombineHiveInputFormat,
        问题是速度可能会很慢,1.1.4以后的版本包括1.1.4已经解决了CombineHiveInputFormat慢的问题。
     (2)hive.mergejob.maponly为false,使用有reduce的MR job来合并小文件。
    

    规避方法:

    (1)加上distribute by rand(12345)或者是distribute by 某个字段,如果结果很小,可以减少reduce数。
    (2)没有加上distribute by,但是第二步的merge很慢,set hive.mergejob.maponly=false;
    

    example:

     select * from r_auction_auctions 
     where  pt='20111205000000' and if_online=0
     and auction_id = 13033941674; 
    

    改为

     set mapred.reduce.tasks=5;
     select * from r_auction_auctions 
     where  pt='20111205000000' and if_online=0
     and auction_id = 13033941674 
     distribute by rand(12345);
    

    3.11.2 merge job使用CombineHiveInputFormat运行很慢

    现象:开发人员写的很多sql很简单,只需要map无需reduce就能完成任务,hive解析sql生成map only的作业,map数很多时,每个map都有至少一个输出结果,在这个MapReduce作业完成后,会起一个合并小文件的Map only作业,它会有一些map产生,各个map使用CombineHiveInputFormat来读取多个小文件,写到一个大文件中。

    问题:合并小文件的job启动以及map运行很慢,从map的日志来看,比如job_201108301259_4048225
    该job是一个合并小文件的作业,该作业输入输出数据量很小,如下:
    Counter Map Reduce Total
    File Systems HDFS bytes read 94,056,452 0 94,056,452
    HDFS bytes written 93,985,955 0 93,985,955

    Job 运行的总的时间:Finished At: 8-Nov-2011 04:04:44 (45mins, 4sec)
    该合并job有3个task,其中一个task运行了43分钟!!!!
    task_201108301259_4048225_m_000000
    8/11 03:20:46 8/11 04:04:38 (43mins, 51sec)

    Task的日志,截取了一部分:

    2011-11-08 03:21:30,764 INFO org.apache.hadoop.hive.ql.exec.TableScanOperator: 0 forwarding 100000 rows
    2011-11-08 03:21:30,764 INFO ExecMapper: ExecMapper: processing 100000 rows: used memory = 14294320
    2011-11-08 03:44:49,437 INFO org.apache.hadoop.hive.ql.exec.MapOperator: 2 forwarding 1000000 rows
    2011-11-08 03:44:49,457 INFO org.apache.hadoop.hive.ql.exec.TableScanOperator: 0 forwarding 1000000 rows
    2011-11-08 03:44:49,457 INFO ExecMapper: ExecMapper: processing 1000000 rows: used memory = 42485208
    2011-11-08 04:04:34,807 INFO org.apache.hadoop.hive.ql.exec.MapOperator: 2 forwarding 2000000 rows
    2011-11-08 04:04:34,825 INFO org.apache.hadoop.hive.ql.exec.TableScanOperator: 0 forwarding 2000000 rows
    2011-11-08 04:04:34,826 INFO ExecMapper: ExecMapper: processing 2000000 rows: used memory = 33694880
    2011-11-08 04:04:38,144 INFO org.apache.hadoop.hive.ql.exec.MapOperator: 2 finished. closing... 
    

    其中有两段,前后两条日志的打印时间差在20分钟以上!!!

    原因:这个map需要读取很多小文件,CombineHiveInputFormat之前的做法是依次从namenode获取每个小文件的location信息,对每个小文件跟namenode来一次RPC调用,namenode现在数据量很大,请求很多,所以有时候会花费比较长的时间。

    结论:大量小文件对namenode来说是一种硬伤,对MapReduce job来说也是一个噩梦。

    解决方法:
    (1)业务层面,即sql语句,加入强制distribute by,让它产生reduce,并且把reduce数设小,对namenode和MapReduce job来说都是非常nice的。
    未修改前的sql,比如是:

    from (select thedate ,toprank_id ,if_test ,object_id ,idx ,idx_rank ,idx_last from rpt_extended_toprank t1 where ds = 20111107 and   toprank_conf_type_id = 5+0 ) t1 
    insert overwrite table rpt_topranks_v3_tz partition(ds = 20111107,toprank_id_pt = 11) 
    select thedate ,toprank_id ,if_test ,object_id ,idx ,idx_rank ,idx_last where toprank_id = 11+0;
    

    修改后的sql是:

    set mapred.reduce.tasks=5;
    from (select thedate ,toprank_id ,if_test ,object_id ,idx ,idx_rank ,idx_last from rpt_extended_toprank t1 where ds = 20111107 and  toprank_conf_type_id = 5+0 ) t1 
    insert overwrite table rpt_topranks_v3_tz partition(ds = 20111107,toprank_id_pt = 11) 
    select thedate ,toprank_id ,if_test ,object_id ,idx ,idx_rank ,idx_last where toprank_id = 11+0 
    distribute by rand();
    

    (2)hive 层面,由于目前这些修改没办法一下子上线,所以推荐在业务层面改动。

     (2.1)修改CombineHiveInputFormat获取文件和split信息,一次RPC调用获取整个目录下面的所有文件信息,已完成,待上线。
    (2.2)如果没有数据,不产生空文件,未完成。

    两种解决方法对比:在sql加入distribute by设置合适reduce数相对第二种要好些,因为前者只需要起一道MapReduce作业,调度等待的时间要小。

    3.12 如果发生数据倾斜,怎么找到是哪个key多了呢?

    如果分组很多,第二个MR的Reduce只有一个,需要运行很长时间才能得到结果。

    select mid,url,count(1) as cnt from (
      select * from r_atpanel_log where pt='20111017000000' and pagetype='normal'
    ) subq
    group by mid,url
    order by cnt desc
    limit 15;
    

    可以优化一下,先过滤很多小分组

    select * from (
      select mid,url,count(1) as cnt from (
          select * from r_atpanel_log where pt='20111017000000' and pagetype='normal'
      ) subq
      group by mid,url
    ) subq2
    where cnt >100
    order by cnt desc
    limit 15;
    
  • 相关阅读:
    web 开发之酷炫--- 酷炫展示
    攻城狮的体检
    科技发烧友之智能路由
    科技发烧友之3d吉米投影
    科技发烧友之单反佳能700d中高端
    上海
    视频会议
    机器学习之信息
    filter
    centos 20T硬盘(超过16T)分区
  • 原文地址:https://www.cnblogs.com/hustzzl/p/7888001.html
Copyright © 2011-2022 走看看