hive优化参数map,reduce优化

  • Post author:
  • Post category:其他



硬刚Hive | 4万字基础调优面试小总结 – 知乎 (zhihu.com)



har小文件归档

    --用来控制归档是否可用
    set hive.archive.enabled=true;
    --通知Hive在创建归档时是否可以设置父目录
    set hive.archive.har.parentdir.settable=true;
    --控制需要归档文件的大小
    set har.partfile.size=1099511627776;
    --使用以下命令进行归档:
    ALTER TABLE A ARCHIVE PARTITION(dt='2021-05-07', hr='12');
    --对已归档的分区恢复为原文件:
    ALTER TABLE A UNARCHIVE PARTITION(dt='2021-05-07', hr='12');



hive调优参数

set hive.map.aggr=true; -- 开启 map 端 combiner
    -- 输出合并小文件常用参数
    SET hive.merge.mapfiles = true; -- 默认 true,在 map-only 任务结束时合并小文件
    SET hive.merge.mapredfiles = true; -- 默认 false,在 map-reduce 任务结束时合并小文件
    SET hive.merge.size.per.task = 268435456; -- 默认 256M
    SET hive.merge.smallfiles.avgsize = 16777216; -- 当输出文件的平均大小小于 16m 该值时,启动一个独立的 map-reduce 任务进行文件 merge
    set hive.fetch.task.conversion=more; -- 让可以不走mapreduce任务的,就不走mapreduce任务
    set hive.exec.parallel=true;-- 开启任务并行执行 当一个sql中有多个job时候,且这多个job之间没有依赖,则可以让顺序执行变为并行执行(一般为用到union all的时候)
    set hive.exec.parallel.thread.number=8;-- 同一个sql允许并行任务的最大线程数
    set mapred.job.reuse.jvm.num.tasks=10; -- 设置jvm重用 JVM重用对hive的性能具有非常大的影响,特别是对于很难避免小文件的场景或者task特别多的场景,这类场景大多数执行时间都很短。jvm的启动过程可能会造成相当大的开销,尤其是执行的job包含有成千上万个task任务的情况。
    set mapred.reduce.tasks = 20--  直接设置reduce数量
    set hive.map.aggr=true  -- map端聚合,降低传给reduce的数据量
    set hive.groupby.skewindata=true -- 开启hive内置的数倾优化机制



hive 调优

    hive底层的mapreduce计算引擎的调优,sql的调优,数据倾斜调优,小文件问题的调优,考虑数据本身的问题
    
    eg1 : count(distinct age) 去重之后的年龄是很少的
    
    --   distinct的命令会在内存中构建一个hashtable,查找去重的时间复杂度是O(1);
    --   group by在不同版本间变动比较大,有的版本会用构建hashtable的形式去重,有的版本会通过排序的方式, 排序最优时间复杂度无法到O(1)。另外,第一种方式(group by)去重会转化为两个任务,会消耗更多的磁盘网络I/O资源。
    --   最新的Hive 3.0中新增了 count(distinct) 优化,通过配置 hive.optimize.countdistinct,即使真的出现数据倾斜也可以自动优化,自动改变SQL执行的逻辑。
    --  第二种方式(distinct)比第一种方式(group by)代码简洁,表达的意思简单明了,如果没有特殊的问题,代码简洁就是优!
    
    select count(distinct col) from a;
    select count(1)  from (select col from a group by col) as t;
    
    -- 推测执行优化 开启两个任务看那个先结束
    set hive.mapred.map.tasks.speculative.execution=false
    set hive.mapred.reduce.tasks.speculative.execution=false
    set mapred.map.tasks.speculative.execution=false;
    set mapred.reduce.tasks.speculative.execution=false;
    
    --hivemap数和reduce的个数如何确定 
    
    
    a)假设input目录下有1个文件a,大小为780M,那么hadoop会将该文件a分隔成7个块(6128m的块和112m的块),从而产生7个map数 
    b)假设input目录下有3个文件a,b,c,大小分别为10m,20m,130m,那么hadoop会分隔成4个块(10m,20m,128m,2m),从而产生4个map数 
    即,如果文件大于块大小(128m),那么会拆分,如果小于块大小,则把该文件当成一个块。
    
    有多少个reduce,就会有多少个输出文件



扩展优化

 如果表a只有一个文件,大小为120M,但包含几千万的记录,如果用1个map去完成这个任务,肯定是比较耗时的,这种情况下,我们要考虑将这一个文件合理的拆分成多个,这样就可以用多个map任务去完成。
    
    set mapreduce.job.reduces =10;
    create external table a_1 as
    select * from stg_data.users
    distribute by CAST(RAND() *10 AS INT);
    
    
    select CAST(RAND() *10 AS INT);
    
    这样会将a表的记录,随机的分散到包含10个文件的a_1表中,再用a_1代替上面sql中的a表,则会用10个map任务去完成。
    
    每个map任务处理大于12M(几百万记录)的数据,效率肯定会好很多。
    
    -- 控制map和reduce的个数
    原则: 使大数据量利用合适的map数;使单个map任务处理合适的数据量
    一个是要合并小文件,一个是要把大文件拆成小文件。

控制hive任务的map数

    通过以下方法来在map执行前合并小文件,减少map数:
    set hive.hadoop.supports.splittable.combineinputformat=true;
    -- 执行map前进行小文件合并
    set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;
    set mapred.min.split.size=100000000;
    set mapred.max.split.size=100000000;
    -- 一个节点上split的至少的大小 ,决定了多个data node上的文件是否需要合并
    set mapred.min.split.size.per.node=50000000;
    -- 一个交换机下split的至少的大小,决定了多个交换机上的文件是否需要合并
    set mapred.min.split.size.per.rack=50000000;
    
    参数解释
    100000000表示100M
    set hive.input.format=org.apache.hadoop.hive.ql.io.CombineHiveInputFormat;这个参数表示执行前进行小文件合并
    mapred.min.split.size相当于mapreduce.input.fileinputformat.split.minsize,设置哪一个都一样
    mapred.max.split.size相当于mapreduce.input.fileinputformat.split.maxsize,设置哪一个都一样
    所以根据求splitSize的公式,return Math.max(minSize, Math.min(maxSize, blockSize));
    可以知道,需增加mapper数,则减少这些值;需减少mapper数,则增加这些值,一般就配置这两个值就行了。
    一般来说
    max.split.size >= min.split.size >= min.size.per.node >= min.size.per.node
    优先级
    当四个参数设置矛盾时,系统会自动以优先级最高的参数为准,进行计算
    max.split.size <= min.split.size <= min.size.per.node <= min.size.per.node
    2 结果合并,下面的数值需自行调整
     
    
    set hive.merge.mapfiles=true;   --在Map-only的任务结束时合并小文件
    set hive.merge.mapredfiles=true;  --在Map-Reduce的任务结束时合并小文件
    set hive.merge.size.per.task=128000000;  --合并后文件的大小为128M左右
    set hive.merge.smallfiles.avgsize=128000000;  --当输出文件的平均大小小于128M时,启动一个独立的map-reduce任务进行文件merge

控制hive任务的reduce数

    -- 控制hive任务的reduce数
     reduce个数的设定极大影响任务执行效率,不指定reduce个数的情况下,Hive会猜测确定一个reduce个数,基于以下两个设定:
    hive.exec.reducers.bytes.per.reducer--(每个reduce任务处理的数据量,默认为1000^3=1G) 
    hive.exec.reducers.max              --(每个任务最大的reduce数,默认为999)
    -- eg:
    输入数据量 130M
    每个reduce处理的数据量 64M 
    reduce个数:reducer数=min(1099130m/64m)=3
    
    有多少个reduce,就会有多少个输出文件
    
    -- 调整reduce个数:
    
    -- 调整hive.exec.reducers.bytes.per.reducer参数的值;
    set hive.exec.reducers.bytes.per.reducer=500000000;500M)
    -- 直接设置reduce的值
    set mapred.reduce.tasks = 15;
    
    使大数据量利用合适的reduce数;使单个reduce任务处理合适的数据量



动态分区属性

  动态分区属性:设置为true表示开启动态分区功能(默认为false)
  hive.exec.dynamic.partition=true;
  
  动态分区属性:设置为nonstrict,表示允许所有分区都是动态的(默认为strict) 设置为strict,表示必须保证至少有一个分区是静态的
  hive.exec.dynamic.partition.mode=strict;
  
  动态分区属性:每个mapper或reducer可以创建的最大动态分区个数
  hive.exec.max.dynamic.partitions.pernode=100;
  
  动态分区属性:一个动态分区创建语句可以创建的最大动态分区个数
  hive.exec.max.dynamic.partitions=1000;
  
  动态分区属性:全局可以创建的最大文件个数
  hive.exec.max.created.files=100000;



数据建模 维度建模

  星型模式是以事实表为中心,所有的维度表直接连接在事实表上,像星星一样。星形模式的维度建模由一个事实表和一组维表成,
  a. 维表只和事实表关联,维表之间没有关联;
  b. 每个维表主键为单列,且该主键放置在事实表中,作为两边连接的外键;
  c. 以事实表为核心,维表围绕核心呈星形分布。
  
  
  
  雪花模型
  雪花模式(Snowflake Schema)是对星型模式的扩展。雪花模式的维度表可以拥有其他维度表的,虽然这种模型相比星型更规范一些,但是由于这种模型不太容易理解,维护成本比较高,而且性能方面需要关联多层维表,性能比星型模型要低。
  
  星座模型
  星座模式是星型模式延伸而来,星型模式是基于一张事实表的,而星座模式是基于多张事实表的,而且共享维度信息。前面介绍的两种维度建模方法都是多维表对应单事实表,但在很多时候维度空间内的事实表不止一个,而一个维表也可能被多个事实表用到。在业务发展后期,绝大部分维度建模都采用的是星座模式。
  

[map,reduce优化]: https://blog.csdn.net/qq_46893497/article/details/113864209

```sql
 order by 会对输入做全局排序,因此只有一个reducer,会导致当输入规模较大时,需要较长的计算时间。
  
  sort by不是全局排序,其在数据进入reducer前完成排序,如果设置mapred.reduce.tasks>1, 则sort by只保证每个reducer的输出有序,不保证全局有序。
  
  Distribute by:按照指定的字段对数据进行划分输出到不同的reduce中。
  
  Cluster by:除了具有 distribute by 的功能外还兼具 sort by 的功能。
  
  
  
  
  UDF:单行进入,单行输出
  
  UDAF:多行进入,单行输出
  
  UDTF:单行输入,多行输出
      
  sum_data(聚合)
  ods_data()
  pdm_data()



版权声明:本文为wenwen1542原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。