Hive调优手段


最常用的调优手段

  • Fetch抓取
  • MapJoin
  • 分区裁剪 列裁剪
  • 控制map个数以及reduce个数
  • JVM重用
  • 数据压缩

Fetch的抓取

  • 出现原因

    Hive中对某些情况的查询不必使用MapReduce计算。在这种情况下,Hive可以简单地读取employee对应的存储目录下的文件,然后输出查询结果到控制台。(原则就是能不用MapReduce就不用MapReduce)

    比如以下这几种情况:

    SELECT * FROM score;

    SELECT s_score FROM score;

    SELECT s_score FROM score LIMIT 3;

  • 设置方法

    第一种: 设置配置文件hive-default.xml,有三个取值:none / minimal / more,老版本默认为minimal,新版本默认为more,应该设置为more

    <property>
    <name>hive.fetch.task.conversion</name>
    <value>more</value>
    </property>

    第二种: set hive.fetch.task.conversion=more;


本地模式

  • 出现原因

    在遇到处理大量小文件时,给一个个小文件分配 container 的时间会远远超过数据处理的时间。Hive的本地模式可以设置当输入数据的个数小于多少个输入数据大小小于多少M时就将所有的数据放到一个MapTask和一个ReduceTask中处理

  • 设置方法

    set hive.exec.model.local.auto=true; 开启Hive本地模式,Hive会在适当的时候自动启动

    set hive.exec.mode.local.auto.inputbytes.max=51234560; 当输入数据量小于这个值时启动本地模式,默认值为128M

    set hive.exec.mode.local.auto.input.files.max=10;当输入文件个数小于这个值时启动本地模式,默认值是4个


表的优化

  • 小表 join 大表

    将key相对分散并且数据量小的表放在join的左边,这样既可以减少内存溢出错误发生的几率,又可以使用Group让小的维度表(1000条以下的记录条数)先进内存,在map端完成reduce。

    早起版本需要考虑此种优化方式,现在版本的hive有了一个优化器,可以自动选择出小表,并将小表的数据一次性放到内存

  • 多个表关联时,最好分拆成小段,避免大sql(无法控制中间Job)

  • 大表 join 大表

    原则:尽量减少输入量



    (1) 空key过滤

    有时一些数据表中会出现大量的相同key对应着空字段,如果这些key对应的是异常数据,这时就可以过滤空key来优化Hive的运行速度

    INSERT OVERWRITE TABLE jointable
    SELECT a.* FROM(
    SELECT * FROM nullidtable
    WHERE id is NOT NULL) AS a //过滤空KEY的操作
    JOIN ori AS b
    ON a.id=b.id;

    (2) 空key转换

    如果key对应的不是异常数据,且其对应的值必须包含在join的结果中,那么就可以将主表中key为空的字段赋一个随机值,这样可以使数据随机均匀地分不到不同的reducer上,避免数据倾斜

    set set hive.exec.reducers.bytes.per.reducer=32123456; 设置每个reduce任务处理的数据量

    set mapreduce.job.reduces=7; 设置执行任务的reduce个数

    INSERT OVERWRITE TABLE jointable
    SELECT a.* FROM nullidtable AS a
    LEFT JOIN ori AS b
    ON CASE WHEN a.id is NULL THEN concat('hive',rand()) //如果A表的ID为空,就转换为'hive+生成的随机数字'
    ELSE a.id END = b.id //如果不为空,直接输出a.id
  • MapJoin

    这就是前面提到的,新版本hive自动选择小表的设定

    set hive.auto.convert.join = true; 开启MapJoin,一般默认就是开启的

    set hive.mapjoin.smalltable.filesize=25123456; 设置数据大小是多少值以下为小表,默认是25M

    工作机制:

  • Group By

    一般情况下,Map阶段的Key相同的数据会分发给一个Reduce,如果Key相同的数据过大时就会发生数据倾斜。其实,并不是所有的聚合操作要在Reduce阶段完成,很多聚合操作可以现在Map端进行部分聚合

    set hive.map.aggr = true; 开启在Map端的聚合操作,默认为true

    set hive.groupby.mapaggr.checkinterval = 100000; 在Map端进行聚合操作的条目数目,默认100000条

    set hive.groupby.skewindata = true; 有数据倾斜的时候进行负载均衡,默认是false

    负载均衡的选项设置为true后查询计划会生成两个MapReduce Job

    第一个MapReduce Job中,Map的输出结果会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,在这一步中相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;(这一步主要在做负载均衡)

    第二个MapReduce Job中,会根据预处理的数据结果按照Group By Key分布到Reduce中(这个过程可以保证相同的Group By Key被分布到同一个Reduce中),最后完成最终的聚合操作。(这一步主要在分组)

  • Count (Distinct)

    在数据量很大的情况下,COUNT(DISTINCT)的操作需要用一个ReduceTask来完成,这样这个ReduceTask要处理的数据量巨大,这种情况可以用 先GROUP BY再COUNT 的方法替换,从而优化hive

    比如:

    SELECT COUNT(DISTINCT id)FROM bigtable;

    可以替换为

    SELECT COUNT(id) FROM(
    SELECT id FROM bigtable
    GROUP BY id) AS a;
  • 笛卡尔积

    尽量避免笛卡尔积,即避免join的时候不加on条件,或者无效的on条件,Hive只能使用1个reducer来完成笛卡尔积。

  • 分区剪裁、列剪裁

    尽量只拿需要的列,有分区就要带上分区条件,另外遇到如下情况,尽量先过滤再Join

    SELECT a.id FROM bigtable AS a
    LEFT JOIN ori AS b
    ON a.id=b.id
    WHERE b.id<=10;

    可以替换为

    SELECT a.id FROM bigtable AS a
    LEFT JOIN ori AS b
    ON (b.id<=10 AND a.id=b.id);

    或者

    SELECT a.id FROM bigtable AS a
    LEFT JOIN (
    SELECT id FROM ori
    WHERE id <=10) AS b
    ON a.id=b.id;
  • 动态分区调整

    主要适用于分区表,以第一个表的分区规则,来对应第二个表的分区规则,将第一个表的所有分区,全部拷贝到第二个表中来,第二个表在加载数据的时候,不需要指定分区,直接用第一个表的分区即可

    set hive.exec.dynamic.partition = true; 开启动态分区功能,默认为true

    set hive.exec.dynamic.partition.mode = nonstrict; 设置为非严格模式,strict为严格模式,表示必须至少指定一个分区为静态分区,nonstrict表示允许所有的分区字段都可以使用动态分区)

    set hive.exec.max.dynamic.partitions = 1000; 在所有执行MR的节点上,最大一共可以创建多少个动态分区,默认1000个

    set hive.exec.max.dynamic.partitions.pernode = 100; 在每个执行MR的节点上,最大可以创建多少个动态分区。这是要根据实际情况来决定的,比如拿到的源数据中为一年的数据,这时就需要设置的值就要大于365,否则就会报错

    set hive.exec.max.created.files = 100000; **整个MR Job中,最多可以创建多少个HDFS文件。**在linux系统当中,每个linux用户最多可以开启1024个进程,每一个进程最多可以打开2048个文件,即持有2048个文件句柄,这里设置的值越大,可以打开的文件句柄越大

    set hive.error.on.empty.partition = false; 当有空分区生成时,是否抛出异常。 一般不需要设置

    当不使用动态分区插入数据时,需要手动指定分区值

    INSERT OVERWRITE TABLE ori_partitioned_target
    PARTITION (p_time='20130812')
    SELECT id,time, uid, keyword, url_rank, click_num, click_url
    FROM ori_partitioned;

    使用动态分区插入数据时,不用手动指定分区,但是select最后面的字段,一定要是分区字段,分区字段的值不能是中文

    INSERT OVERWRITE TABLE ori.partitioned_target
    PARTITION (p_time)
    SELECT id, time, uid, keyword ,url_rank, click_num, click_url, p_time
    FROM ori_partitioned;
  • 分桶表

    分桶表可以将大文件按照规则分成多个小文件,也能达到优化hive的效果,详情请见【Hadoop离线基础总结】Hive的基本操作


数据倾斜

  • 概述

    发生数据倾斜的原因在【Hadoop离线基础总结】MapReduce参数优化提到过,就是大量的数据都涌到同一个reduceTask里面去,造成一个reduceTask里面处理得数据量太大,迟迟不能完成。

    通常情况下,Job会通过input的目录产生一个或者多个MapTask。生成MapTask数的主要的决定因素有:input的文件总个数input的文件大小集群设置的文件块大小(128M)

    是不是MapTask数越多越好? 不是。如果一个任务有大量的小文件(远远小于128M),每一个小文件就会产生一个block块,也就会对应产生一个MapTask,这样一个MapTask的启动和初始化时间远远超过了逻辑处理的时间,就会造成资源浪费。而且MapTask同时可执行的数量也是有限的

    那保证每个文件都接近128M是不是就可以了? 不一定。如果有一个文件是127M,它只会用一个MapTask,但这个文件中只有一个或者两个字段,却有上千上万条记录,同时如果Map处理的逻辑也比较复杂的话,用一个MapTask会很耗时

    所以要根据实际情况来 增加 或者 减少Map数

  • 减少Map数(合并小文件)

    set mapred.max.split.size=112345600; 每个切片最大的值

    set mapred.min.split.size.per.node=112345600; 每个节点上切片最小的大小

    set mapred.min.split.size.per.rack=112345600; 每个交换机上切片最小的大小

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

    这些参数表示在执行任务前按照这些参数来合并小文件,前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),进行合并。(蓝字这些我觉得说的不对,弄明白了再来改)

  • 增加Map数

    现在如果只有一个表a,大小为120M,但包含着几千万条记录,如果用一个MapTask去做肯定会很耗时,该怎么做?

    首先,先用DISTRIBUTE BY把表a打散成10个小文件

    set mapreduce.job.reduces =10;

    CREATE TABLE a_1
    SELECT * FROM a
    DISTRIBUTE BY rand(123); //rand(123)=0.7231742029971469 是一个固定值

    完成后用表a_1执行任务,就会同时有10个MapTask去完成任务

    根据实际情况,控制map数量需要遵循两个原则使大数据量利用合适的map数使单个map任务处理合适的数据量

  • 那么,是不是reduce数越多越好?

    不一定。过多的启动和初始化reduce也会消耗时间和资源。另外,相应的reduce数会产生相应的输出文件数,如果要利用这些输出文件作为下一个任务的输入文件的话,过多的输入文件也会产生问题。

    控制reduce数同样也需要遵循那两个原则处理大数据量利用合适的reduce数使单个reduce任务处理数据量大小要合适

  • 调整Reduce

    方法一:估算reduce个数

    set hive.exec.reducers.bytes.per.reducer=256123456; 每个Reduce处理的数据量默认是256MB

    set hive.exec.reducers.max=1009; 每个任务最大的reduce数,默认为1009

    N=min(参数2,总输入数据量/参数1) 计算reduce数公式

    方法二:

    在hadoop的mapred-default.xml文件中修改

    方法三:

    set mapreduce.job.reduces = 15; 设置reduce个数


执行计划

  • 基本语法

    EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query

    比如:EXPLAIN SELECT * FROM course; 或者 EXPLAIN SELECT s_id,AVG(s_score) AS avgScore FROM score GROUP BY s_id;

    还可以查看更为详细的执行计划:EXPLAIN EXTENDED SELECT * FROM course;

并行执行

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

set hive.exec.parallel.thread.number=16; 同一hql最大并行度,默认为8


hive的严格模式

  • 作用

    1.分区表必须要带上分区字段。(对于分区表,除非where语句中含有分区字段过滤条件来限制范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。进行这个限制的原因是,通常分区表都拥有非常大的数据集,而且数据增加迅速。没有进行分区限制的查询可能会消耗令人不可接受的巨大资源来处理这个表)

    2.使用了order by就必须要使用limit语句。(因为order by为了执行排序过程会将所有的结果数据分发到同一个Reducer中进行处理,强制要求用户增加LIMIT语句可以防止Reducer额外执行很长一段时间)

    3.限制笛卡尔积

JVM重用

  • 概述

    Container执行完了MapTask或者ReduceTask之后,不要释放资源,继续给下一个MapTask或者ReduceTask进行执行。

    set mapred.job.reuse.jvm.num.tasks=10; 开启JVM重用

  • 缺点

    开启JVM重用将一直占用task插槽,以便进行重用,直到任务完成后才能释放。如果某个“不平衡的”job中有某几个ReduceTask执行的时间要比其他ReduceTask消耗的时间长的话,那么保留的插槽就会一直空闲着却无法被其他的job使用,直到所有的task都结束了才会释放。

【Hadoop离线基础总结】Hive调优手段的更多相关文章

  1. hive 调优手段

    调优手段 ()利用列裁剪 当待查询的表字段较多时,选取需要使用的字段进行查询,避免直接select *出大表的所有字段,以免当使用Beeline查询时控制台输出缓冲区被大数据量撑爆. ()JOIN避免 ...

  2. (转)hive调优(1) coding调优

    hive 调优(一)coding调优 本人认为hive是很好的工具,目前支持mr,tez,spark执行引擎,有些大公司原来封装的sparksql,开发py脚本,但是目前hive支持spark引擎(不 ...

  3. 【Hive六】Hive调优小结

    Hive调优 Hive调优 Fetch抓取 本地模式 表的优化 小表.大表Join 大表Join大表 MapJoin Group By Count(Distinct) 去重统计 行列过滤 动态分区调整 ...

  4. python内存机制与垃圾回收、调优手段

    目录 一.python的内存机制 二.python的垃圾回收 1. 引用计数 1.1 原理: 1.2 优缺点: 1.4 两种情况: 2. 标记清除 2.1 原理: 2.2 优缺点: 3. 分代回收 3 ...

  5. (转) hive调优(2)

    hive 调优(二)参数调优汇总 在hive调优(一) 中说了一些常见的调优,但是觉得参数涉及不多,补充如下 1.设置合理solt数 mapred.tasktracker.map.tasks.maxi ...

  6. hive 调优(二)参数调优汇总

    在hive调优(一) 中说了一些常见的调优,但是觉得参数涉及不多,补充如下 1.设置合理solt数 mapred.tasktracker.map.tasks.maximum 每个tasktracker ...

  7. 【Hadoop离线基础总结】oozie的安装部署与使用

    目录 简单介绍 概述 架构 安装部署 1.修改core-site.xml 2.上传oozie的安装包并解压 3.解压hadooplibs到与oozie平行的目录 4.创建libext目录,并拷贝依赖包 ...

  8. 【Hadoop离线基础总结】Hue的简单介绍和安装部署

    目录 Hue的简单介绍 概述 核心功能 安装部署 下载Hue的压缩包并上传到linux解压 编译安装启动 启动Hue进程 hue与其他框架的集成 Hue与Hadoop集成 Hue与Hive集成 Hue ...

  9. 【Hadoop离线基础总结】impala简单介绍及安装部署

    目录 impala的简单介绍 概述 优点 缺点 impala和Hive的关系 impala如何和CDH一起工作 impala的架构及查询计划 impala/hive/spark 对比 impala的安 ...

随机推荐

  1. Application.Exit

    Application.Exit:通知winform消息循环退出.Environment.Exit:终止当前进程,返回exitcode给操作系统 Application.Exit会在所有前台线程退出后 ...

  2. Python中赋值、浅拷贝和深拷贝的区别

    前言文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. PS:如有需要Python学习资料的小伙伴可以加点击下方链接自行获取http: ...

  3. python超实用的30 个简短的代码片段(三)

    Python是目前最流行的语言之一,它在数据科学.机器学习.web开发.脚本编写.自动化方面被许多人广泛使用. 它的简单和易用性造就了它如此流行的原因. 如果你正在阅读本文,那么你或多或少已经使用过P ...

  4. linux sysbench : CPU性能测试详解

    1.sysbench基础知识 sysbench的cpu测试是在指定时间内,循环进行素数计算 素数(也叫质数)就是从1开始的自然数中,无法被整除的数,比如2.3.5.7.11.13.17等.编程公式:对 ...

  5. 最简单的懒人springcloud之Eureka(服务注册与发现)

    本文开发软件是STS,是eclipse为springboot项目而生的一个软件,用这个软件开发spring的项目版本都会自己对应的,话不多说直接上代码 springboot版本2.1.8.RELEAS ...

  6. DEV gridview 合并单元格

    private void gv_docargo_CellMerge(object sender, DevExpress.XtraGrid.Views.Grid.CellMergeEventArgs e ...

  7. keras数据集读取

    from tensorflow.python import keras (x_train,y_train),(x_test,y_test) = keras.datasets.cifar100.load ...

  8. 蒲公英 · JELLY技术周刊 Vol.03

    蒲公英 · JELLY技术周刊 Vol.03 「蒲公英」期刊全新升级--JELLY技术周刊!深度挖掘业界热点动态,来自团队大咖的专业点评,带你深入了解团队研究的技术方向. 登高远眺 天高地迥,觉宇宙之 ...

  9. 聊聊Spring Boot Actuator

    概述 在本文中,我们将介绍Spring Boot Actuator.我们将首先介绍基础知识,然后详细讨论Spring Boot 1.x和2.x中的可用内容. 我们将在Spring Boot 1.x中学 ...

  10. 使用openmp进行共享内存编程

    预处理指令pragma:在系统中加入预处理器指令一般是用来允许不是基本c语言规范部分的行为.不支持pragma的编译器会忽略pragma指令提示的那些语句,这样就允许使用pragma的程序在不支持它们 ...