1.fetch抓取
select * from A;这种语句可以直接读取文件,不走MR程序会快很多;
不走MR程序的情况:
在hive-default.xml.template文件中hive.fetch.task.conversion默认是more,老版本hive默认是minimal,该属性修改为more以后,在全局查找、字段查找、limit查找等都不走mapreduce。
设置conversion参数后再执行sql:
hive (default)> set hive.fetch.task.conversion=none;
2.本地模式
适用于hive的输入量很少的情况,把数据集中到一台最近的机器上处理。小数据集优化效果明显;
开启本地模式:hive (default)> set hive.exec.mode.local.auto=true;
执行SQL
关闭本地模式:hive (default)> set hive.exec.mode.local.auto=false;
自适应开启本地模式:
set hive.exec.mode.local.auto=true; //开启本地mr
//设置local mr的最大输入数据量,当输入数据量小于这个值时采用local mr的方式,默认为134217728,即128M
set hive.exec.mode.local.auto.inputbytes.max=51234560;
//设置local mr的最大输入文件个数,当输入文件个数小于这个值时采用local mr的方式,默认为4
set hive.exec.mode.local.auto.input.files.max=10;
3.join
小表驱动大表原则;新版本hsql已经被优化;
原因:小表被加载进入内存,大表通过关联条件,跟小表对比;
新版本hive的优化,会通过类似于oracle的表分析数据,自己确定大表还是小表。
4.mapjoin
场景:某张表的某个分区的数据远远高于其他分区,发生数据倾斜;
在map端进行join操作:
首先是Task A,它是一个Local Task(在客户端本地执行的Task),负责扫描小表b的数据,将其转换成一个HashTable的数据结构,并写入本地的文件中,之后将该文件加载到DistributeCache中。
接下来是Task B,该任务是一个没有Reduce的MR,启动MapTasks扫描大表a,在Map阶段,根据a的每一条记录去和DistributeCache中b表对应的HashTable关联,并直接输出结果。
案例实操:
(1)开启Mapjoin功能
set hive.auto.convert.join = true; 默认为true
执行SQL
5.group by
场景:有一个分组的数据量特别大,就会导致一个reduce的数据处理量特别大,拖慢整个MR程序的运行;此时可以开启group by 的负载均衡参数
实际操作:
(1)是否在Map端进行聚合,默认为True
set hive.map.aggr = true;
(2)在Map端进行聚合操作的条目数目
set hive.groupby.mapaggr.checkinterval = 100000;
(3)有数据倾斜的时候进行负载均衡(默认是false)
set hive.groupby.skewindata = true;
当选项设定为 true,生成的查询计划会有两个MR Job。第一个MR Job中,Map的输出结果会随机分布到Reduce中,每个Reduce做部分聚合操作,并输出结果,这样处理的结果是相同的Group By Key有可能被分发到不同的Reduce中,从而达到负载均衡的目的;第二个MR Job再根据预处理的数据结果按照Group By Key分布到Reduce中(这个过程可以保证相同的Group By Key被分布到同一个Reduce中),最后完成最终的聚合操作。
6.count(distinct)
场景:直接count(A) 只用一个reduce,数据量大只有一个reduce会非常慢;
实际使用:
SELECT count(id) FROM (SELECT id FROM bigtable GROUP BY id) a;
子查询MR多个reduce处理完成后的结果再去用一个reduce统计;
7.笛卡尔积
避免出现笛卡尔积;
8.分区裁剪列裁剪
用到哪个分区就只取哪个分区的值,用到哪些字段就只取哪些字段,减少MR程序的输入数据量;
9.动态分区调整(复制分区表的时候会用到,可以方便一些)
场景:一张有分区的表,将源数据按照原来的分区,插入到第二张表里,第二张表不用再建立分区了。
实际操作:
1)开启动态分区参数设置
(1)开启动态分区功能(默认true,开启)
set hive.exec.dynamic.partition=true;
(2)设置为非严格模式(动态分区的模式,默认strict,表示必须指定至少一个分区为静态分区,nonstrict模式表示允许所有的分区字段都可以使用动态分区。)
set hive.exec.dynamic.partition.mode=nonstrict;
(3)在所有执行MR的节点上,最大一共可以创建多少个动态分区。
set hive.exec.max.dynamic.partitions=1000;
(4)在每个执行MR的节点上,最大可以创建多少个动态分区。该参数需要根据实际的数据来设定。比如:源数据中包含了一年的数据,即day字段有365个值,那么该参数就需要设置成大于365,如果使用默认值100,则会报错。
set hive.exec.max.dynamic.partitions.pernode=100
(5)整个MR Job中,最大可以创建多少个HDFS文件。
在linux系统当中,每个linux用户最多可以开启1024个进程,每一个进程最多可以打开2048个文件,即持有2048个文件句柄,下面这个值越大,就可以打开文件句柄越大
set hive.exec.max.created.files=100000;
(6)当有空分区生成时,是否抛出异常。一般不需要设置。
set hive.error.on.empty.partition=false;
实际操作:
set hive.exec.dynamic.partition = true;
set hive.exec.dynamic.partition.mode = nonstrict;
set hive.exec.max.dynamic.partitions = 1000;
set hive.exec.max.dynamic.partitions.pernode = 100;
set hive.exec.max.created.files = 100000;
set hive.error.on.empty.partition = false;
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;
注意:在PARTITION (month,day)中指定分区字段名即可;
在SELECT子句的最后几个字段,必须对应前面PARTITION (month,day)中指定的分区字段,包括顺序。
查看分区
hive> show partitions ori_partitioned_target;
10.分桶
11.设置适当的Map数和reduce数(常用记住)
减少map数:
场景:如果一个任务有很多小文件(远远小于块大小128m),则每个小文件也会被当做一个块,用一个map任务来完成,而一个map任务启动和初始化的时间远远大于逻辑处理的时间,就会造成很大的资源浪费。而且,同时可执行的map数是受限的。
1.小文件合并
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;
这个参数表示执行前进行小文件合并,前面三个参数确定合并文件块的大小,大于文件块大小128m的,按照128m来分隔,小于128m,大于100m的,按照100m来分隔,把那些小于100m的(包括小文件和分隔大文件剩下的),进行合并。
增多map数:
场景:如果表a只有一个文件,大小为120M,但包含几千万的记录,如果用1个map去完成这个任务,肯定是比较耗时的,这种情况下,我们要考虑将这一个文件合理的拆分成多个,这样就可以用多个map任务去完成。
set mapreduce.job.reduces =10;
合适的reduce数量:
1)调整reduce个数方法一
(1)每个Reduce处理的数据量默认是256MB
hive.exec.reducers.bytes.per.reducer=256123456
(2)每个任务最大的reduce数,默认为1009
hive.exec.reducers.max=1009
(3)计算reducer数的公式
N=min(参数2,总输入数据量/参数1)
2)调整reduce个数方法二
在hadoop的mapred-default.xml文件中修改
设置每个job的Reduce个数
set mapreduce.job.reduces = 15;
3)reduce个数并不是越多越好
1)过多的启动和初始化reduce也会消耗时间和资源;
2)另外,有多少个reduce,就会有多少个输出文件,如果生成了很多个小文件,那么如果这些小文件作为下一个任务的输入,则也会出现小文件过多的问题;
在设置reduce个数的时候也需要考虑这两个原则:处理大数据量利用合适的reduce数;使单个reduce任务处理数据量大小要合适;
12.根据执行计划进行调优(会看执行计划,判断调优方式)
1)基本语法
EXPLAIN [EXTENDED | DEPENDENCY | AUTHORIZATION] query
2)案例实操
(1)查看下面这条语句的执行计划
hive (default)> explain select * from course;
hive (default)> explain select s_id ,avg(s_score) avgscore from score group by s_id;
(2)查看详细执行计划
hive (default)> explain extended select * from course;
hive (default)> explain extended select s_id ,avg(s_score) avgscore from score group by s_id;
13.并行执行(常用,在资源比较空闲的时候可以开启)
场景:hsql会有执行计划,把一个sql分成多个阶段,默认一阶段一阶段(阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段)执行。开启并行,在可以同时执行的阶段,hsql就会同时执行 比如union all的情况:
select * from (select * from A union all select * from B);
set hive.exec.parallel=true; //打开任务并行执行
set hive.exec.parallel.thread.number=16; //同一个sql允许最大并行度,默认为8。 oracle设置这个只能是双数
14.jvm重用(重要,需要掌握)
场景:task数量特别多,且任务执行时间短,频繁的分配资源初始话会浪费大量的时间。
JVM重用可以使得JVM实例在同一个job中重新使用N次。jvm分配的container资源的重用次数设置。通常在10-20之间,具体多少需要根据具体业务场景测试得出。
实际操作:
Hadoop的mapred-site.xml
<property>
<name>mapreduce.job.jvm.numtasks</name>
<value>10</value>
<description>How many tasks to run per jvm. If set to -1, there is
no limit.
</description>
</property>
在hive当中:
set mapred.job.reuse.jvm.num.tasks=10;