一、批改引擎

默认解决引擎是MapReduce

能够批改解决引擎位Spark

批改为Spark引擎后速度晋升10多倍

二、参数设置

2.1、启动时提醒上面须要设置

In order to change the average load for a reducer (in bytes):  set hive.exec.reducers.bytes.per.reducer=<number>In order to limit the maximum number of reducers:  set hive.exec.reducers.max=<number>In order to set a constant number of reducers:  set mapreduce.job.reduces=<number>

reduce数量由以下三个参数决定,
mapred.reduce.tasks(强制指定reduce的工作数量)

hive.exec.reducers.bytes.per.reducer(每个reduce工作解决的数据量,默认为1000^3=1G)

hive.exec.reducers.max(每个工作最大的reduce数,默认为999)

计算reducer数的公式很简略N=min( hive.exec.reducers.max ,总输出数据量/ hive.exec.reducers.bytes.per.reducer )

只有一个reduce的场景:
a、没有group by 的汇总
b、order by
c、笛卡尔积

三、Fetch抓取

Fetch抓取是指,Hive中对某些状况的查问能够不用应用MapReduce计算。例如:SELECT * FROM employees;在这种状况下,Hive能够简略地读取employee对应的存储目录下的文件,而后输入查问后果到控制台。
在hive-default.xml.template文件中hive.fetch.task.conversion默认是more,老版本hive默认是minimal,该属性批改为more当前,在全局查找、字段查找、limit查找等都不走mapreduce。

<property>    <name>hive.fetch.task.conversion</name>    <value>more</value>    <description>      Expects one of [none, minimal, more].      Some select queries can be converted to single FETCH task minimizing latency.      Currently the query should be single sourced not having any subquery and should not have      any aggregations or distincts (which incurs RS), lateral views and joins.      0. none : disable hive.fetch.task.conversion      1. minimal : SELECT STAR, FILTER on partition columns, LIMIT only      2. more  : SELECT, FILTER, LIMIT only (support TABLESAMPLE and virtual columns)    </description></property>

案例实战:

1)把hive.fetch.task.conversion设置成none,而后执行查问语句,都会执行mapreduce程序。hive (default)> set hive.fetch.task.conversion=none;hive (default)> select * from emp;hive (default)> select ename from emp;hive (default)> select ename from emp limit 3;2)把hive.fetch.task.conversion设置成more,而后执行查问语句,如下查问形式都不会执行mapreduce程序。hive (default)> set hive.fetch.task.conversion=more;hive (default)> select * from emp;hive (default)> select ename from emp;hive (default)> select ename from emp limit 3;

四、本地模式

大多数的Hadoop Job是须要Hadoop提供的残缺的可扩展性来解决大数据集的。不过,有时Hive的输出数据量是十分小的。在这种状况下,为查问触发执行工作耗费的工夫可能会比理论job的执行工夫要多的多。对于大多数这种状况,Hive能够通过本地模式在单台机器上解决所有的工作。对于小数据集,执行工夫能够显著被缩短。
用户能够通过设置hive.exec.mode.local.auto的值为true,来让Hive在适当的时候主动启动这个优化。

set hive.exec.mode.local.auto=true;  //开启本地mr//设置local mr的最大输出数据量,当输出数据量小于这个值时采纳local  mr的形式,默认为134217728,即128Mset hive.exec.mode.local.auto.inputbytes.max=50000000;//设置local mr的最大输出文件个数,当输出文件个数小于这个值时采纳local mr的形式,默认为4set hive.exec.mode.local.auto.input.files.max=10;

案例实战:

1)开启本地模式,并执行查问语句hive (default)> set hive.exec.mode.local.auto=true; hive (default)> select * from emp cluster by deptno;Time taken: 1.328 seconds, Fetched: 14 row(s)2)敞开本地模式,并执行查问语句hive (default)> set hive.exec.mode.local.auto=false; hive (default)> select * from emp cluster by deptno;Time taken: 20.09 seconds, Fetched: 14 row(s)

五、表的优化

5.1、小表join大表

  将key绝对扩散,并且数据量小的表放在join的右边,这样能够无效缩小内存溢出谬误产生的几率;再进一步,能够应用mapjoin让小的维度表(1000条以下的记录条数)先进内存。在map端实现reduce。
  理论测试发现:新版的hive曾经对小表JOIN大表和大表JOIN小表进行了优化。小表放在右边和左边曾经没有显著区别。

案例实操1.需要    测试大表JOIN小表和小表JOIN大表的效率2.建大表、小表和JOIN后表的语句// 创立大表create table bigtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';// 创立小表create table smalltable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';// 创立join后表的语句create table jointable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';3.别离向大表和小表中导入数据hive (default)> load data local inpath '/uardata1/hivetest/bigtable' into table bigtable;hive (default)>load data local inpath '/uardata1/hivetest/smalltable' into table smalltable;4.敞开mapjoin性能(默认是关上的)# 因为mapjoin将小表缓存到内存中, 所以此处为了测试大表,小表join, 将mapjoin敞开set hive.auto.convert.join = false;5.执行小表JOIN大表语句insert overwrite table jointableselect b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_urlfrom smalltable sleft join bigtable  bon b.id = s.id;# 三次测试耗时Time taken: 11.304 secondsTime taken: 17.587 secondsTime taken: 10.252 seconds6.执行大表JOIN小表语句insert overwrite table jointableselect b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_urlfrom bigtable  bleft join smalltable  son s.id = b.id;# 三次测试耗时Time taken: 14.343 secondsTime taken: 11.867 secondsTime taken: 13.149 seconds

5.2、大表join大表

5.2.1、空Key

  有时join超时是因为某些key对应的数据太多,而雷同key对应的数据都会发送到雷同的reducer上,从而导致内存不够。此时咱们应该仔细分析这些异样的key,很多状况下,这些key对应的数据是异样数据,咱们须要在SQL语句中进行过滤。例如key对应的字段空,操作如下:

(1)创立原始数据表、空id表、合并后数据表// 创立原始表create table ori(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';// 创立空id表create table nullidtable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';// 创立join后表的语句create table jointable(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) row format delimited fields terminated by '\t';(2)别离加载原始数据和空id数据到对应表中hive (default)> load data local inpath '/uardata1/hivetest/ori' into table ori;hive (default)> load data local inpath '/uardata1/hivetest/nullid' into table nullidtable;(3)测试不过滤空idhive (default)> insert overwrite table jointable select n.* from nullidtable n left join ori o on n.id = o.id;Time taken: 23.255 secondsTime taken: 20.177 seconds(4)测试过滤空id   # 这个理论业务中应用很少,如果某个字段不存在就将数据过滤,其余字段的数据失常,这样会导致数据一个是样本少了,另外其余字段的数据信息变少hive (default)> insert overwrite table jointable select n.* from (select * from nullidtable where id is not null ) n  left join ori o on n.id = o.id;Time taken: 7.946 secondsTime taken: 7.882 seconds

5.2.2、空key转换

  有时尽管某个key为空对应的数据很多,然而相应的数据不是异样数据,必须要蕴含在join的后果中,此时咱们能够表a中key为空的字段赋一个随机的值,使得数据随机平均地分不到不同的reducer上。例如:

5.2.2.1、不随机散布空null值:

(1)设置5个reduce个数set mapreduce.job.reduces = 5;(2)JOIN两张表insert overwrite table jointableselect n.* from nullidtable n left join ori b on n.id = b.id;Time taken: 23.528 secondsTime taken: 21.05 seconds

5.2.2.2、随机散布空null值

(1)设置5个reduce个数set mapreduce.job.reduces = 5;(2)JOIN两张表# 此处将空key转换为随机数据,与原有数据的key保障不会抵触的同时,对空key散列散布insert overwrite table jointableselect n.* from nullidtable n full join ori o on case when n.id is null then concat('hive', rand()) else n.id end = o.id;

5.3、MapJoin

  如果不指定MapJoin或者不合乎MapJoin的条件,那么Hive解析器会将Join操作转换成Common Join,即:在Reduce阶段实现join。容易产生数据歪斜。能够用MapJoin把小表全副加载到内存在map端进行join,防止reducer解决。

5.3.1、开启MapJoin

(1)设置主动抉择Mapjoinset hive.auto.convert.join = true; 默认为true(2)大表小表的阈值设置(默认25M一下认为是小表):set hive.mapjoin.smalltable.filesize=25000000;

5.3.2、MapJoin工作机制

5.3.3、实例

(1)开启Mapjoin性能set hive.auto.convert.join = true; 默认为true(2)执行小表JOIN大表语句insert overwrite table jointableselect b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_urlfrom smalltable sjoin bigtable  bon s.id = b.id;Time taken: 4.817 seconds(3)执行大表JOIN小表语句insert overwrite table jointableselect b.id, b.time, b.uid, b.keyword, b.url_rank, b.click_num, b.click_urlfrom bigtable  bjoin smalltable  son s.id = b.id;Time taken: 5.915 seconds

与5.1、5.2、相比,工夫进步一倍。大小表的前后地位没有什么影响

5.4、 Group By

  默认状况下,Map阶段同一Key数据分发给一个reduce,当一个key数据过大时就歪斜了。
  并不是所有的聚合操作都须要在Reduce端实现,很多聚合操作都能够先在Map端进行局部聚合,最初在Reduce端得出最终后果。

5.4.1、开启Map端聚合参数设置

(1)是否在Map端进行聚合,默认为Truehive.map.aggr = true(2)在Map端进行聚合操作的条目数目hive.groupby.mapaggr.checkinterval = 100000(3)有数据歪斜的时候进行负载平衡(默认是false)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中),最初实现最终的聚合操作。

5.5、Count(Distinct) 去重统计

数据量小的时候无所谓,数据量大的状况下,因为COUNT DISTINCT操作须要用一个Reduce Task来实现,这一个Reduce须要解决的数据量太大,就会导致整个Job很难实现,个别COUNT DISTINCT应用先GROUP BY再COUNT的形式替换:

5.5.1、案例一

1.    创立一张大表hive (default)> create table bigtable(id bigint, time bigint, uid string, keywordstring, url_rank int, click_num int, click_url string) row format delimitedfields terminated by '\t';2.加载数据hive (default)> load data local inpath '/uardata1/hivetest/bigtable' into table bigtable; 3.设置5个reduce个数set mapreduce.job.reduces = 5;4.执行去重id查问hive (default)> select count(distinct id) from bigtable;OK99947Time taken: 3.284 seconds, Fetched: 1 row(s)5.采纳GROUP by去重idhive (default)> select count(id) from (select id from bigtable group by id) a;OK99947Time taken: 3.28 seconds, Fetched: 1 row(s)

尽管会多用一个Job来实现,但在数据量大的状况下,这个相对是值得的。

5.6、笛卡尔积

  尽量避免笛卡尔积,join的时候不加on条件,或者有效的on条件,Hive只能应用1个reducer来实现笛卡尔积。

5.7 行列过滤

  • 列解决:在SELECT中,只拿须要的列,如果有,尽量应用分区过滤,少用SELECT *。
  • 行解决:在分区剪裁中,当应用外关联时,如果将副表的过滤条件写在Where前面,那么就会先全表关联,之后再过滤,比方:

5.7.1、案例一

1.测试先关联两张表,再用where条件过滤hive (default)> select o.id from bigtable bjoin ori o on o.id = b.idwhere o.id <= 10;Time taken: 3.282 seconds, Fetched: 100 row(s)2.通过子查问后,再关联表hive (default)> select b.id from bigtable bjoin (select id from ori where id <= 10 ) o on b.id = o.id;Time taken: 4.232 seconds, Fetched: 100 row(s)

5.8、动静分区调整

  关系型数据库中,对分区表Insert数据时候,数据库主动会依据分区字段的值,将数据插入到相应的分区中,Hive中也提供了相似的机制,即动静分区(Dynamic Partition),只不过,应用Hive的动静分区,须要进行相应的配置

5.8.1、开启动静分区参数设置

(1)开启动静分区性能(默认true,开启)    hive.exec.dynamic.partition=true(2)设置为非严格模式(动静分区的模式,默认strict,示意必须指定至多一个分区为动态分区,nonstrict模式示意容许所有的分区字段都能够应用动静分区。)    hive.exec.dynamic.partition.mode=nonstrict(3)在所有执行MR的节点上,最大一共能够创立多少个动静分区。    hive.exec.max.dynamic.partitions=1000(4)在每个执行MR的节点上,最大能够创立多少个动静分区。该参数须要依据理论的数据来设定。比方:源数据中蕴含了一年的数据,即day字段有365个值,那么该参数就须要设置成大于365,如果应用默认值100,则会报错。    hive.exec.max.dynamic.partitions.pernode=100(5)整个MR Job中,最大能够创立多少个HDFS文件。    hive.exec.max.created.files=100000(6)当有空分区生成时,是否抛出异样。个别不须要设置。    hive.error.on.empty.partition=false

5.8.2、案例一

需要:将ori中的数据依照工夫(如:20111230000008),插入到指标表ori_partitioned_target的相应分区中。

(1)创立分区表create table ori_partitioned(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) partitioned by (p_time bigint) row format delimited fields terminated by '\t';(2)加载数据到分区表中hive (default)> load data local inpath '/uardata1/hivetest/ds1' into table ori_partitioned partition(p_time='20200730000010') ;hive (default)> load data local inpath '/uardata1/hivetest/ds2' into table ori_partitioned partition(p_time='20200730000011') ;(3)创立指标分区表create table ori_partitioned_target(id bigint, time bigint, uid string, keyword string, url_rank int, click_num int, click_url string) PARTITIONED BY (p_time STRING) row format delimited fields terminated by '\t';(4)设置动静分区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;hive (default)> 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;(5)查看指标分区表的分区状况hive (default)> show partitions ori_partitioned_target;

关注我的公众号【宝哥大数据】, 更多干货