核心思想:是将hive程序当做mapreduce程序进行优化
我们知道大数据场景下,不怕数据量大,就怕数据倾斜,特别要慎用count(distinct),count(distinct)容易产生倾斜问题。
先来说说hive中sql语句转化为MapReduce的过程:
整个编译过程分为6个阶段:
定义Sql的语法规则,完成SQL词法,语法解析,将SQL转化为 抽象语法树AST Tree。
2.遍历抽象语法树AST Tree,抽象出查询的基本组成单元 QueryBlock查询块。
3.遍历QueryBlock,翻译为执行操作树OperatorTree。
4.逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量。
5.遍历OperatorTree,翻译为MapReduce任务。
6.物理层优化器进行MapReduce任务的变换,生成最终的执行计划。
1.查看执行计划:
explain extended select count(*) from table;
可以查看整个sql的执行过程:
的运行方式
1.集群模式:需要先将本地程序打成Jar包,上传集群,如果执行出错,需要继续修改上传,在执行jar包,循环往复,影响开发效率。
2.本地模式:在hive中执行 set =true;
只能在测试和开发环境进行,并且限制输入文件的大小不能超过128M,如果大于该配置,仍会以集群方式运行。对于小数据执行时间可以明显被缩短。
没有开启本地模式:33.121秒
开启本地模式(3.578秒):
3.并行执行:
一次SQL计算中允许并行执行的job个数的最大值,Hive会将一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。由于job包含多个阶段,而这些阶段并非完全互相依赖,所以可以启用并行执行,缩短整个job的执行时间(硬件资源充足,默认并行度是8)
设置参数:
4.严格模式(用于用户的某些查询操作):
hive通过设置以下参数模式开启严格执行模式:
set =strict;(默认情况:strict严格模式,nonstrict非严格模式)
查询限制:
1.对于分区表,必须添加where对于子句的查询,必须添加分区列,否则根本查询不了。
by语句必须包含limit输出限制,因为执行order by会将所有数据进行一次全排序,会将所有数据导入内存,执行排序,添加limit后会将数据打散分治计算,在mapper端和reducer端都会执行推测机制,避免了数据倾斜。
3.限制笛卡尔积的查询。
5.排序方式:
order by :对于查询结果做全排序,只允许有一个reduce处理 ,会造成数据倾斜, 一般不建议使用。严格模式下,必须结合limit来使用。
sort by :对于单个reduce的数据进行排序,分区内数据有序。
distribute by: 分区排序,分区间有序。经常和sort by结合使用
(distribute by column sort by column asc|desc的方式)
cluster by: sort by+distribute by,无法指定升序和降序规则。
Join
Map Join:在map端完成join(shuffle比较浪费时间,如果没有了reduce也就没有了shuffle)
两种实现方式:
1、SQL方式,在SQL语句中添加MapJoin标记(mapjoin hint)
手动:
SELECT /*+ MAPJOIN(smallTable) */ ,
FROM smallTable JOIN bigTable ON =
会优先将一张小表(默认小于25M,可以需要适当调节)的数据加载进内存中,然后大表的数据通过map端进行读取,然后和内存进行匹配,内存的计算速度很高,这样就在内存端进行了操作,不需要shuffle,不需要reduce
自动的mapjoin:
通过修改以下配置启用mapjoin:
set = true;(该参数为true时,Hive自动对左边的表统计量,如果是小表就加入内存,即对小表使用Map join)
相关配置参数:
;
(大表小表判断的阈值,如果表的大小小于该值则会被加载到内存中运行)
手动和自动产生冲突,解决:
;
(默认值:true;是否忽略手动mapjoin hint 即mapjoin标记)
合并mapjoin
;
(默认值:true;将普通的join转化为普通的mapjoin时,是否将多个mapjoin转化为一个mapjoin)
;
(将多个mapjoin转化为一个mapjoin时,其表的最大值)
当三个表以上的表关联的时候,尽可能适用相同的连接键。会转化为一个mapreduce作业。
大表join大表(本质是reduce数据分布不均匀做成的数据倾斜)了解
空key过滤:有时join超时是因为某些key对应的数据太多,而相同key对应的数据都会发送到相同的reducer上,从而导致内存不够。此时我们应该仔细分析这些异常的key,很多情况下,这些key对应的数据是异常数据,我们需要在SQL语句中进行过滤。
空key转换:有时虽然某个key为空对应的数据很多,但是相应的数据不是异常数据,必须要包含在join的结果中,此时我们可以表a中key为空的字段赋一个随机的值,使得数据随机均匀地分不到不同的reducer上。
7.map_side聚合
是否在map端执行combine
聚合比例:大于0.5不会聚合,反之发生聚合,预先会测试100000条数据
通过设置以下参数开启在Map端的聚合:
set =true;
相关配置参数:
:
map端group by执行聚合时处理的多少行数据(默认:100000)
:
进行聚合的最小比例(预先对100000条数据做聚合,若聚合之后的数据量/100000的值大于该配置0.5,则不会聚合)
:
map端聚合使用的内存的最大值
:
map端做聚合操作是hash表的最大可用内容,大于该值则会触发flush
是否对GroupBy产生的数据倾斜做优化,默认为false
将mapreduce变成两个MR,一个将数据进行均匀随机分布,第二个将指定的比例(0.5)往不同的reduce分发。虽然会慢一些,但是不会崩溃。注意(33%,66%,99%)
8.合并小文件
文件数目小,容易在文件存储端造成压力,给hdfs造成压力,影响效率.,将map和reduce的小文件进行合并,大于256M后不再参与合并
设置合并属性
是否合并map输出文件:=true
是否合并reduce输出文件:=true;
合并文件的大小:=256*1000*1000
9.去重统计
数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替换
10.控制Hive中Map及Reduce的数量
Map数量相关的参数
一个split的最大值,即每个map处理文件的最大值
一个节点上split的最小值
一个机架上split的最小值
Reduce数量相关的参数
强制指定reduce任务的数量
每个reduce任务处理的数据量
每个任务最大的reduce数
重用
预先申请了一些资源,避免了重复对资源的重复申请和销毁工作
适用场景:
1.小文件数过多
个数过多
通过 set =n; 来设置
(n为task插槽个数)
缺点:设置开启之后,task插槽会一直占用资源,不论是否有task运行,直到所有的task即整个job全部执行完成时,才会释放所有的task插槽资源!