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. CSS躬行记(6)——滤镜

    滤镜(filter)可改造元素的视觉呈现,CSS内置的滤镜有10种,通过SVG文件还能自定义滤镜. 一.调色滤镜 调色滤镜可控制元素的模糊.颜色.亮度等变化,并且多个滤镜可组合在一起使用.这些滤镜大部 ...

  2. 全平台阅读器 StartReader

    前段时间在网上闲逛, 发现了一款全平台阅读器 StartReader, 用了一阵子感觉还不错,网址是: https://www.startreader.com/ 感觉这款阅读器是程序员的福音,it人员 ...

  3. HTML学习过程-(1)

    记录我HTML的学习 (1) 最开始学习html是在因为在听北京理工大学教授讲的网络公开课上.当时老师讲的是网络爬虫,因为要爬取特定网页的信息,需要借助[正则表达式](https://baike.ba ...

  4. MergeSort归并排序和利用归并排序计算出数组中的逆序对

    首先先上LeetCode今天的每日一题(面试题51. 数组中的逆序对): 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. ...

  5. Java中的方法是什么以及方法的书写格式

    方法:完成特定功能的代码块注意:在很多语言里面有函数的定义,而在Java中函数被称为方法.方法格式:修饰符 返回值类型+ 方法名 (参数类型 参数名1,参数类型 参数名2...){方法体语句;retu ...

  6. HTTPS之密钥知识与密钥工具Keytool和Keystore-Explorer

    1 简介 之前文章<Springboot整合https原来这么简单>讲解过一些基础的密码学知识和Springboot整合HTTPS.本文将更深入讲解密钥知识和密钥工具. 2 密钥知识-非对 ...

  7. Linux下jdk的安装和环境变量的配置

    Linux下jdk的安装和环境变量的配置 一.jdk的下载 方式一:在官网下载 http://www.oracle.com/technetwork/java/javase/downloads/inde ...

  8. Apache Rewrite实现URL的跳转和域名跳转

    Apache Rewrite实现URL的跳转和域名跳转   Rewirte主要的功能就是实现URL的跳转,它的正则表达式是基于Perl语言.可基 于服务器级的(httpd.conf)和目录级的 (.h ...

  9. Galera将死——MySQL Group Replication正式发布

    2016-12-14 来源:InsideMySQL 作者:姜承尧 MySQL Group Replication GA 很多同学表示昨天的从你的全世界路过画风不对,好在今天MySQL界终于有大事情发生 ...

  10. js高阶函数的理解

    高阶函数:英文叫Higher-order function.JavaScript的函数其实都指向某个变量.既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数 ...