核心思想:是将hive程序当做mapreduce程序进行优化;
hive中sql语句转化为MapReduce的过程,整个编译过程分为6个阶段:
1).Antlr定义Sql的语法规则,完成SQL词法,语法解析,将SQL转化为 抽象语法树AST Tree。
2).遍历抽象语法树AST Tree,抽象出查询的基本组成单元 QueryBlock查询块。
3).遍历QueryBlock,翻译为执行操作树OperatorTree。
4).逻辑层优化器进行OperatorTree变换,合并不必要的ReduceSinkOperator,减少shuffle数据量。
5).遍历OperatorTree,翻译为MapReduce任务。
6).物理层优化器进行MapReduce任务的变换,生成最终的执行计划。
1、 显示查询计划:
在hive命令行输入:explain extended select count(*) from bigdata_user;
可以查看该sql执行的整个过程。
2、hive的运行方式:
1).集群模式:需要先将本地程序打成Jar包,上传集群,如果执行出错,需要继续修改上传,在执行jar包,循环往复,影响开发效率。
2).本地模式:在hive中执行 set hive.exec.mode.local.auto=true;
只能在测试和开发环境进行,并且限制输入文件的大小不能超过128M,如果大于该配置,仍会以集群方式运行。对于小数据执行时间可以明显被缩短。
3、并行执行:
一次SQL计算中允许并行执行的job个数的最大值,Hive会将一个查询转化成一个或者多个阶段。这样的阶段可以是MapReduce阶段、抽样阶段、合并阶段、limit阶段。由于job包含多个阶段,而这些阶段并非完全互相依赖,所以可以启用并行执行,缩短整个job的执行时间(硬件资源充足,默认并行度是8)
设置参数:hive.exec.parallel.number
4、 严格模式:
设置参数为:
set hive.mapred.mode = strict;
1)、笛卡尔积查询:join查询不使用on语句而是使用where语句
关系型数据库的执行优化器可以高效地将where语句转化成on语句,hive并不会执行这种优化。
2)、查询没有选择分区:对于分区表,where语句中无分区字段过滤条件
不允许用户扫描所有分区,因为分区表通常数据量巨大,没有限制分区的查询可能会消耗巨大资源。
3)、order by没有limit语句:
order by 为了执行排序过程,会将所有的结果数据分发到同一个reducer中进行处理,增加limit语句可以防止reducer额外执行很长一段时间。
4)、int类型数据与string和double类型比较
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,无法指定升序和降序规则。
6、Hive Join
如果不指定MapJoin或者不符合MapJoin的条件,那么Hive解析器会默认把执行Common Join,即在Reduce阶段完成join。整个过程包含Map、Shuffle、Reduce阶段。Map Join:在map端完成join,没有了Shuffle,就没有Reduce。节省查询时间。
1)、SQL方式,在SQL语句中添加MapJoin标记(mapjoin hint)
语法:
SELECT /*+ MAPJOIN(smallTable) */ smallTable.key, bigTable.value
FROM smallTable JOIN bigTable ON smallTable.key = bigTable.key;
2)、开启自动的MapJoin
通过修改以下配置启用自动的mapjoin:
set hive.auto.convert.join = true;
(该参数为true时,Hive自动对左边的表统计量,如果是小表就加入内存,即对小表使用Map join)
相关配置参数:
hive.mapjoin.smalltable.filesize;
(大表小表判断的阈值,如果表的大小小于该值则会被加载到内存中运行)
hive.ignore.mapjoin.hint;
(默认值:true;是否忽略mapjoin hint 即mapjoin标记)
hive.auto.convert.join.noconditionaltask;
(默认值:true;将普通的join转化为普通的mapjoin时,是否将多个mapjoin转化为一个mapjoin)
hive.auto.convert.join.noconditionaltask.size;
(将多个mapjoin转化为一个mapjoin时,其表的最大值)
7.map_side聚合
是否在map端执行combine
通过设置以下参数开启在Map端的聚合:
set hive.map.aggr=true;
相关配置参数:
hive.groupby.mapaggr.checkinterval:
map端group by执行聚合时处理的多少行数据(默认:100000)
hive.map.aggr.hash.min.reduction:
进行聚合的最小比例(预先对100000条数据做聚合,若聚合之后的数据量/100000的值大于该配置0.5,则不会聚合)
8、合并小文件
每个小文件会启动一个map任务,浪费资源;
文件数目小,容易在文件存储端造成压力,给hdfs造成压力,影响效率.;
将map和reduce的小文件进行合并,大于256M后不再参与合并;
设置合并属性
是否合并map输出文件:hive.merge.mapfiles=true
是否合并reduce输出文件:hive.merge.mapredfiles=true;
合并文件的大小:hive.merge.size.per.task=256*1000*1000
9、去重统计
数据量小的时候无所谓,数据量大的情况下,由于COUNT DISTINCT操作需要用一个Reduce Task来完成,这一个Reduce需要处理的数据量太大,就会导致整个Job很难完成,一般COUNT DISTINCT使用先GROUP BY再COUNT的方式替换。
10、控制Hive中Map及Reduce的数量
1)、Map数量相关的参数
mapred.max.split.size
一个split的最大值,即每个map处理文件的最大值
一个机架上split的最小值
mapred.min.split.size.per.rack
一个节点上split的最小值
mapred.min.split.size.per.node
一个split的最大值,即每个map处理文件的最大值
2)、Reduce数量相关的参数
mapred.reduce.tasks
强制指定reduce任务的数量
hive.exec.reducers.bytes.per.reducer
每个reduce任务处理的数据量
hive.exec.reducers.max
每个任务最大的reduce数
11、JVM重用
预先申请了一些资源,避免了重复对资源的重复申请和销毁工作(类似于线程池)
适用场景:
1)、小文件数过多
2)、task个数过多
通过 set mapred.job.reuse.jvm.num.tasks=n; 来设置(n为task插槽个数)
缺点:设置开启之后,task插槽会一直占用资源,不论是否有task运行,直到所有的task即整个job全部执行完成时,才会释放所有的task插槽资源!