Hive----Hive的优化常用小结

本文总结了Hive的基础知识,包括数据管理、内部表与外部表、分区和桶的概念。探讨了Hive的优化方法,如Map和Reduce的优化策略,如Map端聚合、调整Map和Reduce任务数量,以及通过分区裁剪、MapJoin和多插入优化查询性能。还提到了数据倾斜的问题及其解决办法,如数据分布均匀化和特定操作的优化策略。

基础回顾

  • H i v e 数据管理

    •  hive的表本质就是Hadoop的目录/文件 
    • hive默认表存放路径一般都是在你工作目录的hive目录里面,按表名做文件夹分开,如果你 有分区表的话,分区值是子文件夹,可以直接在其它的M/R job里直接应用这部分数据
    •  NameHDFS Directory
      Tablemobile_user /lbs/mobile_user
      Partitionaction = insight, day= 20190406/lbs/mobile_user/action=insight/day=20190406
      Bucketclusted by user into 32 buckets /lbs/mobile_user/action=insight/day=20190406/part-00000
  • H i v e 内部表和外部表

    • Hive的create创建表的时候,选择的创建方式:
      • – create table
      • – create external table
    • 特点: 
      • 在导入数据到外部表,数据并没有移动到自己的数据仓库目录下,也就是说外部表中的数据并不是由它 自己来管理的!而表则不一样; 
      • 在删除表的时候,Hive将会把属于表的元数据和数据全部删掉;而删除外部表的时候,Hive仅仅删除 外部表的元数据,数据是不会删除的!
  • H i v e 中的P a r t i t i o n

    • 在 Hive 中,表中的一个 Partition 对应于表下的一个目录,所有的 Partition 的 数据都存储在对应的目录中 
      • – 例如:pvs 表中包含 ds 和 city 两个 Partition,则
      • – 对应于 ds = 20190406, ctry = US 的 HDFS 子目录为:/wh/pvs/ds=20190406/ctry=US;
      • – 对应于 ds = 20190406, ctry = CA 的 HDFS 子目录为;/wh/pvs/ds=20190406/ctry=CA 
    • partition是辅助查询,缩小查询范围,加快数据的检索速度和对数据按照一定的 规格和条件进行管理。
  • H i v e 中的B u c k e t

    • hive中table可以拆分成partition,table和partition可以通过‘CLUSTERED BY ’进一步分bucket,bucket中的数据可以通过‘SORT BY’排序。 
    • create table bucket_user (id int,name string)clustered by (id) into 4 buckets; 
    • 'set hive.enforce.bucketing = true' 可以自动控制上一轮reduce的数量从而适配bucket的个数,当然,用户也可以自主设置mapred.reduce.tasks去适配 bucket个数
    •  Bucket主要作用: 
      • 数据sampling 
      • 提升某些查询操作效率,例如mapside join
    • 查看sampling数据: 
      •  – hive> select * from student tablesample(bucket 1 out of 2 on id); 

      • – tablesample是抽样语句,语法:TABLESAMPLE(BUCKET x OUT OF y) 

      • – y必须是table总bucket数的倍数或者因子。hive根据y的大小,决定抽样的比例。例如,table总共分了64份,当y=32 时,抽取(64/32=)2个bucket的数据,当y=128时,抽取(64/128=)1/2个bucket的数据。x表示从哪个bucket开始抽 取。例如,table总bucket数为32,tablesample(bucket 3 out of 16),表示总共抽取(32/16=)2个bucket的数据 ,分别为第3个bucket和第(3+16=)19个bucket的数据。

H i v e 的优化

  • Map的优化: 

    • – 作业会通过input的目录产生一个或者多个map任务。set dfs.block.size(=128) 
    • – Map越多越好吗?是不是保证每个map处理接近文件块的大小? 
    • – 如何合并小文件,减少map数?
       
      • set mapred.max.split.size=100000000;

        set mapred.min.split.size.per.node=100000000;

        set mapred.min.split.size.per.rack=100000000;

        set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;

    • 如何适当的增加map数?

      • set mapred.map.tasks=10;

    • – Map端聚合 hive.map.aggr=true 。 Mr中的Combiners.

  • Reduce的优化: 

    • – hive.exec.reducers.bytes.per.reducer = 10;reduce任务处理的数据量 
    • – 调整reduce的个数:
      • 设置reduce处理的数据量
      • set mapred.reduce.tasks=100 (优先)
    • 什么时候会存在只有1个reduce的情况?
      • 1)没有group by
      • 2)使用order by
        • 优化:distribute by和sort by结合起来
        • order by:全局排序   
        • sort by:不是全局排序,数据进入reducer之前做的排序   
        • distribute by:控制map端如何拆分数据给reduce
      • 3)笛卡尔积
        • 优化:join的时候用on
  • 加快查询速度

    • 分区裁剪(partition) 

      • – Where中的分区条件,会提前生效,不必特意做子查询,直接Join和GroupBy 
    • 笛卡尔积 

      • – join的时候不加on条件或者无效的on条件,Hive只能使用1个reducer来完成笛卡尔积 
    • Map join 

      • – /*+ MAPJOIN(tablelist) */,必须是小表,不要超过1G,或者50万条记录 
    • Union all 

      • – 先做union all再做join或group by等操作可以有效减少MR过程,尽管是多个Select,最终只有一个 mr
    • Multi-insert & multi-group by 

      • – 从一份基础表中按照不同的维度,一次组合出不同的数据 
      • FROM from_statement
            INSERT OVERWRITE TABLE tablename1 [PARTITION (partcol1=val1)] select_statement1 group by key1
            INSERT OVERWRITE TABLE tablename2 [PARTITION(partcol2=val2 )] select_statement2 group by key2 

         

    • Automatic merge 

      • – 当文件大小比阈值小时,hive会启动一个mr进行合并 
      • – hive.merge.mapfiles = true 是否和并 Map 输出文件,默认为 True 
      • – hive.merge.mapredfiles = false 是否合并 Reduce 输出文件,默认为 False 
      • – hive.merge.size.per.task = 256*1000*1000 合并文件的大小 
    • Multi-Count Distinct 

      • – 必须设置参数:set hive.groupby.skewindata=true; 
      • – select  dt,  count(distinct uniq_id),  count(distinct ip) from ods_log where dt=20170301 group by dt ;
      • 如果功能开启,目的是负载均衡
  • H i v e 的 J o i n 优化 

    • 注意:

      • 一个MR job
        • SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (a.key = c.key1)
      • 生成多个MR job
        • SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
    • 表连接顺序

      • 按照JOIN顺序中的最后一个表应该尽量是大表,因为JOIN前一阶段生成的数据会存在于 Reducer的buffer中,通过stream最后面的表,直接从Reducer的buffer中读取已经缓冲的中间 结果数据(这个中间结果数据可能是JOIN顺序中,前面表连接的结果的Key,数据量相对较小, 内存开销就小),这样,与后面的大表进行连接时,只需要从buffer中读取缓存的Key,与大表 中的指定Key进行连接,速度会更快,也可能避免内存缓冲区溢出。
      • SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1); a表被视为大表
      • SELECT /*+ MAPJOIN(b) */ a.key, a.value FROM a JOIN b ON a.key = b.key;
        MAPJION会把小表全部读入内存中,在map阶 段直接拿另外一个表的数据和内存中表数据做 匹配,由于在map是进行了join操作,省去了 reduce运行的效率也会高很多.
      • 左连接时,左表中出现的JOIN字段都保留,右表没有连接上的都为空。
        • 1.  SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key) WHERE a.ds='2019-04-04' AND b.ds='2019-04-04'
        • 2.  SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key AND b.ds='2019-04-04' AND a.ds='20019-04-04')
        • 上面两种方式的结果是一致的,但是更好的是第二种!执行顺序是,首先完成2表JOIN,然后再通过WHERE条件进行过滤,这样在JOIN过程中可能会 输出大量结果,再对这些结果进行过滤,比较耗时。可以进行优化,将WHERE条件放在ON后 ,在JOIN的过程中,就对不满足条件的记录进行了预先过滤。
    • 并行执行 

      • 同步执行hive的多个阶段,hive在执行过程,将一个查询转化成一个或者多个阶段。某个特 定的job可能包含众多的阶段,而这些阶段可能并非完全相互依赖的,也就是说可以并行执行 的,这样可能使得整个job的执行时间缩短。
      • hive执行开启:set hive.exec.parallel=true
  • 数据倾斜 

    • 操作
      • Join
      • Group by
      • Count Distinct 
    • 原因 
      • key分布不均导致的 
      • 人为的建表疏忽
      • 业务数据特点
    • 症状 
      • 任务进度长时间维持在99%(或100%),查看任务监控页面,发现只有少量(1个或几个)reduce子任务未完成。 
      • 查看未完成的子任务,可以看到本地读写数据量积累非常大,通常超过10GB可以认定为发生数据倾斜。 
    • 倾斜度 
      • 平均记录数超过50w且最大记录数是超过平均记录数的4倍。
      • 最长时长比平均时长超过4分钟,且最大时长超过平均时长的2倍。 
    • 万能方法 
      • hive.groupby.skewindata=true
  • 数据倾斜——大小表关联

    • 原因

      • Hive在进行join时,按照join的key进行分发,而在join左边的表的数据会首先读入内存,如果左边表的key相对 分散,读入内存的数据会比较小,join任务执行会比较快;而如果左边的表key比较集中,而这张表的数据量很大, 那么数据倾斜就会比较严重,而如果这张表是小表,则还是应该把这张表放在join左边。
    • 思路 

      • 将key相对分散,并且数据量小的表放在join的左边,这样可以有效减少内存溢出错误发生的几率 
      • 使用map join让小的维度表先进内存。
    • 方法 

      • Small_table join big_table
  • 数据倾斜——大大表关联

    • 原因 

      • 日志中有一部分的userid是空或者是0的情况,导致在用user_id进行hash分桶的时候,会将日志中userid为0或者 空的数据分到一起,导致了过大的斜率。
    • 思路

      • 把空值的key变成一个字符串加上随机数,把倾斜的数据分到不同的reduce上,由于null值关联不上,处理后并不 影响最终结果。
    • 方法

      • on case when (x.uid = '-' or x.uid = '0‘ or x.uid is null) then concat('dp_hive_search',rand()) else x.uid end = f.user_id;
  • 数据倾斜——大大表关联(业务削减)

    • 案例 

      • Select * from dw_log t join dw_user t1 on t.user_id=t1.user_id 
      • 现象:两个表都上千万,跑起来很悬 
    • 思路

      • 当天登陆的用户其实很少 
    • 方法 

      • Select/*+MAPJOIN(t12)*/ * 
        from dw_log t11 
        join ( 
        	select/*+MAPJOIN(t)*/ t1.* 
        	from ( 
        		select user_id from dw_log group by user_id 
        	) t 
        	join dw_user t1 
        	on t.user_id=t1.user_id 
        ) t12 
        on t11.user_id=t12.user_id;

         

  • 数据倾斜——聚合时存在大量特殊值

    • 原因

      • 做count distinct时,该字段存在大量值为NULL或空的记录。
    • 思路

      • count distinct时,将值为空的情况单独处理,如果是计算count distinct,可以不用处理,直接过滤,在最后结 果中加1。 
      • 如果还有其他计算,需要进行group by,可以先将值为空的记录单独处理,再和其他计算结果进行union
    • 方法

      • select cast(count(distinct(user_id))+1 as bigint) as user_cnt 
        from tab_a 
        where user_id is not null and user_id <> '';

         

  • 数据倾斜——空间换时间 

    • 案例 

      •  Select day,count(distinct session_id),count(distinct user_id) from log a group by day 
    • 问题 

      • 同一个reduce上进行distinct操作时压力很大 
    • 方法

      • select day, 
        	count(case when type='session' then 1 else null end) as session_cnt, 
        	count(case when type='user' then 1 else null end) as user_cnt 
        from (       
        	select day,session_id,type 
        	from ( 
        		select day,session_id,'session' as type 
        		from log 
        		union all 
        		select day user_id,'user' as type 
        		from log 
        	) 
        	group by day,session_id,type 
        ) t1 
        group by day

         

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值