zoukankan      html  css  js  c++  java
  • hive优化总结

    Hivehql注意事项

    1、使用分区裁剪,列裁剪

    在分区剪裁中,当使用外关联时,如果将副表的过滤条件写在Where后面,那么就会先全表关联,之后再过滤,

    SELECT a.id

    FROM lxw1234_a a

    left outer joint_lxw1234_partitioned b

    ON (a.id = b.url);

    WHEREb.day = 2015-05-10

    使用SELECT a.id

    FROM lxw1234_a a

    left outer joint_lxw1234_partitioned b

    ON (a.id =b.url AND b.day = 2015-05-10);

    或者直接写成子查询:

    SELECT a.id

    FROM lxw1234_a a

    left outer join(SELECT url FROM t_lxw1234_partitioned WHERE day = 2015-05-10) b

    ON (a.id = b.url)

    这两者的效果相同

    列裁剪就不会导致全表扫描

    2、少用COUNTDISTINCT

    数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BYCOUNT的方式替换:

    SELECT day,

    COUNT(DISTINCT id)AS uv

    FROM lxw1234

    GROUP BY day

    可以转换成:

    SELECT day,

    COUNT(id) AS uv

    FROM (SELECTday,id FROM lxw1234 GROUP BY day,id) a

    GROUP BY day;

    虽然会多用一个Job来完成,但在数据量大的情况下,这个绝对是值得的。

    还有就是distinct会多启动一个job,如果不是有意义的distinct的就不要使用

    3、是否存在多对多的关联

    只要遇到表关联,就必须得调研一下,是否存在多对多的关联,起码得保证有一个表或者结果集的关联键不重复。

    如果某一个关联键的记录数非常多,那么分配到该Reduce Task中的数据量将非常大,导致整个Job很难完成,甚至根本跑不出来。

    还有就是避免笛卡尔积,同理,如果某一个键的数据量非常大,也是很难完成Job的。

    关联键请参考后面的join详解

    4、合理使用MapJoin

    参考后面的join详解

    5、并行执行job

    set hive.exec.parallel=true;   //打开任务并行执行

    set hive.exec.parallel.thread.number=16; //同一个sql允许最大并行度,默认为8。

    子查询并行也可以提供并行度,前提是资源足够

    数据倾斜的处理

    导致数据倾斜的操作GROUP BY, COUNTDISTINCT, join

     原因:key分布不均匀、业务数据本身特点

    办法:

    1、 使用COUNT DISTINCTGROUP BY造成的数据倾斜:

    存在大量空值或NULL,或者某一个值的记录特别多,可以先把该值过滤掉,在最后单独处理:

    多重COUNT DISTINCT通常使用UNION ALL +ROW_NUMBER() + SUM + GROUP BY来变通实现。

    2、使用JOIN引起的数据倾斜关联键存在大量空值或者某一特殊值,

    ”NULL”空值单独处理,不参与关联,空值或特殊值加随机数作为关联键;

    不同数据类型的字段关联转换为同一数据类型之后再做关联

    3、控制Map数和Reduce

    a、控制hive任务中的map

    不是map越多越好也不是越少越好,小文件太多导致map太多,从而map的启动和初始化时间远远大于逻辑处理时间,就会造成资源的浪费

    也不是map的处理的文件越接近128M越好,如果map处理的业务逻辑过于复杂,就会比较耗时,

    所以针对小文件个数比较多就要合并小文件,减少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;
    再执行上面的语句,用了74个map任务,map消耗的计算资源:SLOTS_MILLIS_MAPS= 333,500
    对于这个简单SQL任务,执行时间上可能差不多,但节省了一半的计算资源。
    大概解释一下,100000000表示100M, sethive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;这个参数表示执行前进行小文件合并,
    前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),
    进行合并,最终生成了74个块。

    遇到文件比较大且处理逻辑复杂时,适当增加map个数

    Select data_desc,
    count(1),
    count(distinct id),
    sum(case when …),
    sum(case when …),
    sum(…)
    from a group by data_desc
    如果表a只有一个文件,大小为120M,但包含几千万的记录,如果用1个map去完成这个任务,肯定是比较耗时的,这种情况下,我们要考虑将这一个文件合理的拆分成多个,
    这样就可以用多个map任务去完成。
    set mapred.reduce.tasks=10;
    create table a_1 as
    select * from a
    distribute by rand(123);

    这样会将a表的记录,随机的分散到包含10个文件的a_1表中,再用a_1代替上面sql中的a表,则会用10个map任务去完成。
    每个map任务处理大于12M(几百万记录)的数据,效率肯定会好很多。

    控制map数量需要遵循两个原则:使大数据量利用合适的map数;使单个map任务处理合适的数据量;

    b、控制hive任务的reduce

    hive.exec.reducers.bytes.per.reducer(每个reduce任务处理的数据量,默认为1000^3=1G)
    hive.exec.reducers.max(每个任务最大的reduce数,默认为999)
    计算reducer数的公式很简单N=min(参数2,总输入数据量/参数1)

    调整reduce个数的方法

    1、调整hive.exec.reducers.bytes.per.reducer参数的值;
    set hive.exec.reducers.bytes.per.reducer=500000000; (500M)

    2、set mapred.reduce.tasks = 15;

    reduce个数并不是越多越好

    以下情况会出现不管怎么都只会有一个reduce的情况

    1、没有group by的汇总,比如把select pt,count(1) from popt_tbaccountcopy_mes where pt =‘2012-07-04′ group by pt; 写成 select count(1) frompopt_tbaccountcopy_mes where pt = ‘2012-07-04′;

    2、用了Order by会进行全表的统计

    3、有笛卡尔积

    详解hivejoin

    Hive中的Join可分为Common Join(Reduce阶段完成join)和Map Join(Map阶段完成join)。本文简单介绍一下两种join的原理和机制

    Hive中Join的关联键必须在ON ()中指定,不能在Where中指定,否则就会先做笛卡尔积,再过滤。

    1、Hive Common Join

    如果不指定MapJoin或者不符合MapJoin的条件,那么Hive解析器会将Join操作转换成Common Join,即:在Reduce阶段完成join.
    整个过程包含Map、Shuffle、Reduce阶段。

    • Map阶段

    读取源表的数据,Map输出时候以Join on条件中的列为key,如果Join有多个关联键,则以这些关联键的组合作为key;
    Map输出的value为join之后所关心的(select或者where中需要用到的)列;同时在value中还会包含表的Tag信息,用于标明此value对应哪个表;
    按照key进行排序

    • Shuffle阶段

    根据key的值进行hash,并将key/value按照hash值推送至不同的reduce中,这样确保两个表中相同的key位于同一个reduce中

    • Reduce阶段
      根据key的值完成join操作,期间通过Tag来识别不同表中的数据。
    1. 以下面的HQL为例,图解其过程:
    2. SELECT
    3. a.id,a.dept,b.age
    4. FROM a join b
    5. ON (a.id = b.id);

     

    2、Hive Map Join

    MapJoin通常用于一个很小的表和一个大表进行join的场景,具体小表有多小,由参数hive.mapjoin.smalltable.filesize来决定,该参数表示小表的总大小,默认值为25000000字节,即25M。

    Hive0.7之前,需要使用hint提示 /*+ mapjoin(table) */才会执行MapJoin,否则执行Common Join,但在0.7版本之后,默认自动会转换Map Join,由参数hive.auto.convert.join来控制,默认为true.

    仍然以9.1中的HQL来说吧,假设a表为一张大表,b为小表,并且hive.auto.convert.join=true,那么Hive在执行时候会自动转化为MapJoin。

    • 如图中的流程,首先是Task A,它是一个Local Task(在客户端本地执行的Task),负责扫描小表b的数据,将其转换成一个HashTable的数据结构,并写入本地的文件中,之后将该文件加载到DistributeCache中
    • 接下来是Task B,该任务是一个没有Reduce的MR,启动MapTasks扫描大表a,在Map阶段,根据a的每一条记录去和DistributeCache中b表对应的HashTable关联,并直接输出结果。
    • 由于MapJoin没有Reduce,所以由Map直接输出结果文件,有多少个Map Task,就有多少个结果文件。

    mapjoin比common join多了一步,首先启动了一个本地的Map Reduce作业,读d表,

    然后启动了一个非本地的Map Reduce作业,是一个真实的Map操作,读e表,

    然后并没有启动真实的Reduce操作,而直接在Map端进行了join操作,最后展示数据。

    使用优化器将commmon join 优化成mapjoin,省掉了Reduce操作,效率更高。

     

     count() count(if) count(distinct if) sum(if)的用法和区别

    博客地址https://www.cnblogs.com/zzhangyuhang/p/9799303.html

    如:

    --初步统计域名数据到临时表中

    INSERT OVERWRITE TABLE tmp.tmp_table_arch_50x_report_access_${date}

    SELECT host,count(1) AS req_cnt,

    sum(if(status in (500,502,503,504),1,0)) as error_cnt

    from ods.ods_table_log_vps_ngx_access

    where dt="${date}"

    GROUP BY host

    采用这种方式不用group by两个字段,并且可以统计出来

     

  • 相关阅读:
    测试面试题
    订单怎么测试?(主要测试订单的状态变化)
    还款功能怎么测试?
    登录功能怎么测试?
    apache配置详解与实践
    apache的安装
    linux系统优化(关闭SElinux、防火墙)
    linux网络配置
    linux的日志管理
    python的xlwt模块
  • 原文地址:https://www.cnblogs.com/lrxvx/p/11005257.html
Copyright © 2011-2022 走看看