转:Hive SQL的编译过程

Hive是基于Hadoop的一个数据仓库系统,在各大公司都有普遍的应用。美团数据仓库也是基于Hive搭建,天天执行近万次的Hive ETL计算流程,负责天天数百GB的数据存储和分析。Hive的稳定性和性能对咱们的数据分析很是关键。python

在几回升级Hive的过程当中,咱们遇到了一些大大小小的问题。经过向社区的咨询和本身的努力,在解决这些问题的同时咱们对Hive将SQL编译为MapReduce的过程有了比较深刻的理解。对这一过程的理解不只帮助咱们解决了一些Hive的bug,也有利于咱们优化Hive SQL,提高咱们对Hive的掌控力,同时有能力去定制一些须要的功能。sql

MapReduce实现基本SQL操做的原理

详细讲解SQL编译为MapReduce以前,咱们先来看看MapReduce框架实现SQL基本操做的原理apache

Join的实现原理

select u.name, o.orderid from order o join user u on o.uid = u.uid;

在map的输出value中为不一样表的数据打上tag标记,在reduce阶段根据tag判断数据来源。MapReduce的过程以下(这里只是说明最基本的Join的实现,还有其余的实现方式)数组

 MapReduce CommonJoin的实现

Group By的实现原理

select rank, isonline, count(*) from city group by rank, isonline;

将GroupBy的字段组合为map的输出key值,利用MapReduce的排序,在reduce阶段保存LastKey区分不一样的key。MapReduce的过程以下(固然这里只是说明Reduce端的非Hash聚合过程)缓存

 MapReduce Group By的实现

Distinct的实现原理

select dealid, count(distinct uid) num from order group by dealid;

当只有一个distinct字段时,若是不考虑Map阶段的Hash GroupBy,只须要将GroupBy字段和Distinct字段组合为map输出key,利用mapreduce的排序,同时将GroupBy字段做为reduce的key,在reduce阶段保存LastKey便可完成去重app

 MapReduce Distinct的实现

若是有多个distinct字段呢,以下面的SQL框架

select dealid, count(distinct uid), count(distinct date) from order group by dealid;

实现方式有两种:编辑器

(1)若是仍然按照上面一个distinct字段的方法,即下图这种实现方式,没法跟据uid和date分别排序,也就没法经过LastKey去重,仍然须要在reduce阶段在内存中经过Hash去重ide

 MapReduce Multi Distinct的实现

(2)第二种实现方式,能够对全部的distinct字段编号,每行数据生成n行数据,那么相同字段就会分别排序,这时只须要在reduce阶段记录LastKey便可去重。工具

这种实现方式很好的利用了MapReduce的排序,节省了reduce阶段去重的内存消耗,可是缺点是增长了shuffle的数据量。

须要注意的是,在生成reduce value时,除第一个distinct字段所在行须要保留value值,其他distinct数据行value字段都可为空。

 MapReduce Multi Distinct的实现

SQL转化为MapReduce的过程

了解了MapReduce实现SQL基本操做以后,咱们来看看Hive是如何将SQL转化为MapReduce任务的,整个编译过程分为六个阶段:

  1. Antlr定义SQL的语法规则,完成SQL词法,语法解析,将SQL转化为抽象语法树AST Tree
  2. 遍历AST Tree,抽象出查询的基本组成单元QueryBlock
  3. 遍历QueryBlock,翻译为执行操做树OperatorTree
  4. 逻辑层优化器进行OperatorTree变换,合并没必要要的ReduceSinkOperator,减小shuffle数据量
  5. 遍历OperatorTree,翻译为MapReduce任务
  6. 物理层优化器进行MapReduce任务的变换,生成最终的执行计划

下面分别对这六个阶段进行介绍

Phase1 SQL词法,语法解析

Antlr

Hive使用Antlr实现SQL的词法和语法解析。Antlr是一种语言识别的工具,能够用来构造领域语言。
这里不详细介绍Antlr,只须要了解使用Antlr构造特定的语言只须要编写一个语法文件,定义词法和语法替换规则便可,Antlr完成了词法分析、语法分析、语义分析、中间代码生成的过程。

Hive中语法规则的定义文件在0.10版本之前是Hive.g一个文件,随着语法规则愈来愈复杂,由语法规则生成的Java解析类可能超过Java类文件的最大上限,0.11版本将Hive.g拆成了5个文件,词法规则HiveLexer.g和语法规则的4个文件SelectClauseParser.g,FromClauseParser.g,IdentifiersParser.g,HiveParser.g。

抽象语法树AST Tree

通过词法和语法解析后,若是须要对表达式作进一步的处理,使用 Antlr 的抽象语法树语法Abstract Syntax Tree,在语法分析的同时将输入语句转换成抽象语法树,后续在遍历语法树时完成进一步的处理。

下面的一段语法是Hive SQL中SelectStatement的语法规则,从中能够看出,SelectStatement包含select, from, where, groupby, having, orderby等子句。
(在下面的语法规则中,箭头表示对于原语句的改写,改写后会加入一些特殊词标示特定语法,好比TOK_QUERY标示一个查询块)

selectStatement
   :
   selectClause
   fromClause
   whereClause?
   groupByClause?
   havingClause?
   orderByClause?
   clusterByClause?
   distributeByClause?
   sortByClause?
   limitClause? -> ^(TOK_QUERY fromClause ^(TOK_INSERT ^(TOK_DESTINATION ^(TOK_DIR TOK_TMP_FILE))
                     selectClause whereClause? groupByClause? havingClause? orderByClause? clusterByClause?
                     distributeByClause? sortByClause? limitClause?))
   ;

样例SQL

为了详细说明SQL翻译为MapReduce的过程,这里以一条简单的SQL为例,SQL中包含一个子查询,最终将数据写入到一张表中

FROM
( 
  SELECT
    p.datekey datekey,
    p.userid userid,
    c.clienttype
  FROM
    detail.usersequence_client c
    JOIN fact.orderpayment p ON p.orderid = c.orderid
    JOIN default.user du ON du.userid = p.userid
  WHERE p.datekey = 20131118 
) base
INSERT OVERWRITE TABLE `test`.`customer_kpi`
SELECT
  base.datekey,
  base.clienttype,
  count(distinct base.userid) buyer_count
GROUP BY base.datekey, base.clienttype

SQL生成AST Tree

Antlr对Hive SQL解析的代码以下,HiveLexerX,HiveParser分别是Antlr对语法文件Hive.g编译后自动生成的词法解析和语法解析类,在这两个类中进行复杂的解析。

HiveLexerX lexer = new HiveLexerX(new ANTLRNoCaseStringStream(command));    //词法解析,忽略关键词的大小写
TokenRewriteStream tokens = new TokenRewriteStream(lexer);
if (ctx != null) {
  ctx.setTokenRewriteStream(tokens);
}
HiveParser parser = new HiveParser(tokens);                                 //语法解析
parser.setTreeAdaptor(adaptor);
HiveParser.statement_return r = null;
try {
  r = parser.statement();                                                   //转化为AST Tree
} catch (RecognitionException e) {
  e.printStackTrace();
  throw new ParseException(parser.errors);
}

最终生成的AST Tree以下图右侧(使用Antlr Works生成,Antlr Works是Antlr提供的编写语法文件的编辑器),图中只是展开了骨架的几个节点,没有彻底展开。
子查询1/2,分别对应右侧第1/2两个部分。

 SQL生成AST Tree

这里注意一下内层子查询也会生成一个TOK_DESTINATION节点。请看上面SelectStatement的语法规则,这个节点是在语法改写中特地增长了的一个节点。缘由是Hive中全部查询的数据均会保存在HDFS临时的文件中,不管是中间的子查询仍是查询最终的结果,Insert语句最终会将数据写入表所在的HDFS目录下。

详细来看,将内存子查询的from子句展开后,获得以下AST Tree,每一个表生成一个TOK_TABREF节点,Join条件生成一个“=”节点。其余SQL部分相似,不一一详述。

 AST Tree

Phase2 SQL基本组成单元QueryBlock

AST Tree仍然很是复杂,不够结构化,不方便直接翻译为MapReduce程序,AST Tree转化为QueryBlock就是将SQL进一部抽象和结构化。

QueryBlock

QueryBlock是一条SQL最基本的组成单元,包括三个部分:输入源,计算过程,输出。简单来说一个QueryBlock就是一个子查询。

下图为Hive中QueryBlock相关对象的类图,解释图中几个重要的属性

  • QB#aliasToSubq(表示QB类的aliasToSubq属性)保存子查询的QB对象,aliasToSubq key值是子查询的别名
  • QB#qbp即QBParseInfo保存一个基本SQL单元中的给个操做部分的AST Tree结构,QBParseInfo#nameToDest这个HashMap保存查询单元的输出,key的形式是inclause-i(因为Hive支持Multi Insert语句,因此可能有多个输出),value是对应的ASTNode节点,即TOK_DESTINATION节点。类QBParseInfo其他HashMap属性分别保存输出和各个操做的ASTNode节点的对应关系。
  • QBParseInfo#JoinExpr保存TOK_JOIN节点。QB#QBJoinTree是对Join语法树的结构化。
  • QB#qbm保存每一个输入表的元信息,好比表在HDFS上的路径,保存表数据的文件格式等。
  • QBExpr这个对象是为了表示Union操做。

 QueryBlock

AST Tree生成QueryBlock

AST Tree生成QueryBlock的过程是一个递归的过程,先序遍历AST Tree,遇到不一样的Token节点,保存到相应的属性中,主要包含如下几个过程

  • TOK_QUERY => 建立QB对象,循环递归子节点
  • TOK_FROM => 将表名语法部分保存到QB对象的aliasToTabs等属性中
  • TOK_INSERT => 循环递归子节点
  • TOK_DESTINATION => 将输出目标的语法部分保存在QBParseInfo对象的nameToDest属性中
  • TOK_SELECT => 分别将查询表达式的语法部分保存在destToSelExprdestToAggregationExprsdestToDistinctFuncExprs三个属性中
  • TOK_WHERE => 将Where部分的语法保存在QBParseInfo对象的destToWhereExpr属性中

最终样例SQL生成两个QB对象,QB对象的关系以下,QB1是外层查询,QB2是子查询

QB1

  \

   QB2

Phase3 逻辑操做符Operator

Operator

Hive最终生成的MapReduce任务,Map阶段和Reduce阶段均由OperatorTree组成。逻辑操做符,就是在Map阶段或者Reduce阶段完成单一特定的操做。

基本的操做符包括TableScanOperator,SelectOperator,FilterOperator,JoinOperator,GroupByOperator,ReduceSinkOperator

从名字就能猜出各个操做符完成的功能,TableScanOperator从MapReduce框架的Map接口原始输入表的数据,控制扫描表的数据行数,标记是从原表中取数据。JoinOperator完成Join操做。FilterOperator完成过滤操做

ReduceSinkOperator将Map端的字段组合序列化为Reduce Key/value, Partition Key,只可能出如今Map阶段,同时也标志着Hive生成的MapReduce程序中Map阶段的结束。

Operator在Map Reduce阶段之间的数据传递都是一个流式的过程。每个Operator对一行数据完成操做后以后将数据传递给childOperator计算。

Operator类的主要属性和方法以下

  • RowSchema表示Operator的输出字段
  • InputObjInspector outputObjInspector解析输入和输出字段
  • processOp接收父Operator传递的数据,forward将处理好的数据传递给子Operator处理
  • Hive每一行数据通过一个Operator处理以后,会对字段从新编号,colExprMap记录每一个表达式通过当前Operator处理先后的名称对应关系,在下一个阶段逻辑优化阶段用来回溯字段名
  • 因为Hive的MapReduce程序是一个动态的程序,即不肯定一个MapReduce Job会进行什么运算,多是Join,也多是GroupBy,因此Operator将全部运行时须要的参数保存在OperatorDesc中,OperatorDesc在提交任务前序列化到HDFS上,在MapReduce任务执行前从HDFS读取并反序列化。Map阶段OperatorTree在HDFS上的位置在Job.getConf(“hive.exec.plan”) + “/map.xml”

 QueryBlock

QueryBlock生成Operator Tree

QueryBlock生成Operator Tree就是遍历上一个过程当中生成的QB和QBParseInfo对象的保存语法的属性,包含以下几个步骤:

  • QB#aliasToSubq => 有子查询,递归调用
  • QB#aliasToTabs => TableScanOperator
  • QBParseInfo#joinExpr => QBJoinTree => ReduceSinkOperator + JoinOperator
  • QBParseInfo#destToWhereExpr => FilterOperator
  • QBParseInfo#destToGroupby => ReduceSinkOperator + GroupByOperator
  • QBParseInfo#destToOrderby => ReduceSinkOperator + ExtractOperator

因为Join/GroupBy/OrderBy均须要在Reduce阶段完成,因此在生成相应操做的Operator以前都会先生成一个ReduceSinkOperator,将字段组合并序列化为Reduce Key/value, Partition Key

接下来详细分析样例SQL生成OperatorTree的过程

先序遍历上一个阶段生成的QB对象

  1. 首先根据子QueryBlock QB2#aliasToTabs {du=dim.user, c=detail.usersequence_client, p=fact.orderpayment}生成TableScanOperator

    TableScanOperator(“dim.user”) TS[0]
     TableScanOperator(“detail.usersequence_client”) TS[1]        TableScanOperator(“fact.orderpayment”) TS[2]
  2. 先序遍历QBParseInfo#joinExpr生成QBJoinTree,类QBJoinTree也是一个树状结构,QBJoinTree保存左右表的ASTNode和这个查询的别名,最终生成的查询树以下

    base
        /  \
       p    du
      /      \
     c        p
  1. 前序遍历QBJoinTree,先生成detail.usersequence_clientfact.orderpayment的Join操做树

 Join to Operator

图中 TS=TableScanOperator RS=ReduceSinkOperator JOIN=JoinOperator

  1. 生成中间表与dim.user的Join操做树

 Join to Operator

  1. 根据QB2 QBParseInfo#destToWhereExpr 生成FilterOperator。此时QB2遍历完成。

下图中SelectOperator在某些场景下会根据一些条件判断是否须要解析字段。

 Where to Operator

图中 FIL= FilterOperator SEL= SelectOperator

  1. 根据QB1的QBParseInfo#destToGroupby生成ReduceSinkOperator + GroupByOperator

 GroupBy to Operator

图中 GBY= GroupByOperator
GBY[12]是HASH聚合,即在内存中经过Hash进行聚合运算

  1. 最终都解析完后,会生成一个FileSinkOperator,将数据写入HDFS

 FileSinkOperator

图中FS=FileSinkOperator

Phase4 逻辑层优化器

大部分逻辑层优化器经过变换OperatorTree,合并操做符,达到减小MapReduce Job,减小shuffle数据量的目的。

名称

做用

② SimpleFetchOptimizer

优化没有GroupBy表达式的聚合查询

② MapJoinProcessor

MapJoin,须要SQL中提供hint,0.11版本已不用

② BucketMapJoinOptimizer

BucketMapJoin

② GroupByOptimizer

Map端聚合

① ReduceSinkDeDuplication

合并线性的OperatorTreepartition/sort key相同的reduce

① PredicatePushDown

谓词前置

① CorrelationOptimizer

利用查询中的相关性,合并有相关性的JobHIVE-2206

ColumnPruner

字段剪枝

表格中①的优化器均是一个Job干尽量多的事情/合并。②的都是减小shuffle数据量,甚至不作Reduce。

CorrelationOptimizer优化器很是复杂,都能利用查询中的相关性,合并有相关性的Job,参考 Hive Correlation Optimizer

对于样例SQL,有两个优化器对其进行优化。下面分别介绍这两个优化器的做用,并补充一个优化器ReduceSinkDeDuplication的做用

PredicatePushDown优化器

断言判断提早优化器将OperatorTree中的FilterOperator提早到TableScanOperator以后

 PredicatePushDown

NonBlockingOpDeDupProc优化器

NonBlockingOpDeDupProc优化器合并SEL-SEL 或者 FIL-FIL 为一个Operator

 NonBlockingOpDeDupProc

ReduceSinkDeDuplication优化器

ReduceSinkDeDuplication能够合并线性相连的两个RS。实际上CorrelationOptimizer是ReduceSinkDeDuplication的超集,能合并线性和非线性的操做RS,可是Hive先实现的ReduceSinkDeDuplication

譬以下面这条SQL语句

from (select key, value from src group by key, value) s select s.key group by s.key;

通过前面几个阶段以后,会生成以下的OperatorTree,两个Tree是相连的,这里没有画到一块儿

 ReduceSinkDeDuplication

这时候遍历OperatorTree后能发现前先后两个RS输出的Key值和PartitionKey以下

 

Key

PartitionKey

childRS

key

key

parentRS

key,value

key,value

ReduceSinkDeDuplication优化器检测到:1. pRS Key彻底包含cRS Key,且排序顺序一致;2. pRS PartitionKey彻底包含cRS PartitionKey。符合优化条件,会对执行计划进行优化。

ReduceSinkDeDuplication将childRS和parentheRS与childRS之间的Operator删掉,保留的RS的Key为key,value字段,PartitionKey为key字段。合并后的OperatorTree以下:

 ReduceSinkDeDuplication

Phase5 OperatorTree生成MapReduce Job的过程

OperatorTree转化为MapReduce Job的过程分为下面几个阶段

  1. 对输出表生成MoveTask
  2. 从OperatorTree的其中一个根节点向下深度优先遍历
  3. ReduceSinkOperator标示Map/Reduce的界限,多个Job间的界限
  4. 遍历其余根节点,遇过碰到JoinOperator合并MapReduceTask
  5. 生成StatTask更新元数据
  6. 剪断Map与Reduce间的Operator的关系

对输出表生成MoveTask

由上一步OperatorTree只生成了一个FileSinkOperator,直接生成一个MoveTask,完成将最终生成的HDFS临时文件移动到目标表目录下

MoveTask[Stage-0]
Move Operator

开始遍历

将OperatorTree中的全部根节点保存在一个toWalk的数组中,循环取出数组中的元素(省略QB1,未画出)

 开始遍历

取出最后一个元素TS[p]放入栈 opStack{TS[p]}中

Rule #1 TS% 生成MapReduceTask对象,肯定MapWork

发现栈中的元素符合下面规则R1(这里用python代码简单表示)

"".join([t + "%" for t in opStack]) == "TS%"

生成一个MapReduceTask[Stage-1]对象,MapReduceTask[Stage-1]对象的MapWork属性保存Operator根节点的引用。因为OperatorTree之间之间的Parent Child关系,这个时候MapReduceTask[Stage-1]包含了以TS[p]为根的全部Operator

 Stage-1 生成Map阶段

Rule #2 TS%.*RS% 肯定ReduceWork

继续遍历TS[p]的子Operator,将子Operator存入栈opStack中
当第一个RS进栈后,即栈opStack = {TS[p], FIL[18], RS[4]}时,就会知足下面的规则R2

"".join([t + "%" for t in opStack]) == "TS%.*RS%"

这时候在MapReduceTask[Stage-1]对象的ReduceWork属性保存JOIN[5]的引用

 Stage-1 生成Reduce阶段

Rule #3 RS%.*RS% 生成新MapReduceTask对象,切分MapReduceTask

继续遍历JOIN[5]的子Operator,将子Operator存入栈opStack中

当第二个RS放入栈时,即当栈opStack = {TS[p], FIL[18], RS[4], JOIN[5], RS[6]}时,就会知足下面的规则R3

"".join([t + "%" for t in opStack]) == “RS%.*RS%” //循环遍历opStack的每个后缀数组

这时候建立一个新的MapReduceTask[Stage-2]对象,将OperatorTree从JOIN[5]RS[6]之间剪开,并为JOIN[5]生成一个子Operator FS[19]RS[6]生成一个TS[20]MapReduceTask[Stage-2]对象的MapWork属性保存TS[20]的引用。

新生成的FS[19]将中间数据落地,存储在HDFS临时文件中。

 Stage-2

继续遍历RS[6]的子Operator,将子Operator存入栈opStack中

opStack = {TS[p], FIL[18], RS[4], JOIN[5], RS[6], JOIN[8], SEL[10], GBY[12], RS[13]}时,又会知足R3规则

同理生成MapReduceTask[Stage-3]对象,并切开 Stage-2 和 Stage-3 的OperatorTree

 Stage-3

R4 FS% 链接MapReduceTask与MoveTask

最终将全部子Operator存入栈中以后,opStack = {TS[p], FIL[18], RS[4], JOIN[5], RS[6], JOIN[8], SEL[10], GBY[12], RS[13], GBY[14], SEL[15], FS[17]} 知足规则R4

"".join([t + "%" for t in opStack]) == “FS%”

这时候将MoveTaskMapReduceTask[Stage-3]链接起来,并生成一个StatsTask,修改表的元信息

 MoveTask

合并Stage

此时并无结束,还有两个根节点没有遍历。

将opStack栈清空,将toWalk的第二个元素加入栈。会发现opStack = {TS[du]}继续知足R1 TS%,生成MapReduceTask[Stage-5]

 Stage-5

继续从TS[du]向下遍历,当opStack={TS[du], RS[7]}时,知足规则R2 TS%.*RS%

此时将JOIN[8]保存为MapReduceTask[Stage-5]ReduceWork时,发如今一个Map对象保存的Operator与MapReduceWork对象关系的Map<Operator, MapReduceWork>对象中发现,JOIN[8]已经存在。此时将MapReduceTask[Stage-2]MapReduceTask[Stage-5]合并为一个MapReduceTask

 合并 Stage-2 和 Stage-5

同理从最后一个根节点TS[c]开始遍历,也会对MapReduceTask进行合并

 合并 Stage-1 和 Stage-6

切分Map Reduce阶段

最后一个阶段,将MapWork和ReduceWork中的OperatorTree以RS为界限剪开

 切分Map Reduce阶段

OperatorTree生成MapReduceTask全貌

最终共生成3个MapReduceTask,以下图

 OperatorTree生成MapReduceTask全貌

Phase6 物理层优化器

这里不详细介绍每一个优化器的原理,单独介绍一下MapJoin的优化器

名称

做用

Vectorizer

HIVE-4160,将在0.13中发布

SortMergeJoinResolver

bucket配合,相似于归并排序

SamplingOptimizer

并行order by优化器,在0.12中发布

CommonJoinResolver + MapJoinResolver

MapJoin优化器

MapJoin原理

 mapjoin原理

MapJoin简单说就是在Map阶段将小表读入内存,顺序扫描大表完成Join。

上图是Hive MapJoin的原理图,出自Facebook工程师Liyin Tang的一篇介绍Join优化的slice,从图中能够看出MapJoin分为两个阶段:

  1. 经过MapReduce Local Task,将小表读入内存,生成HashTableFiles上传至Distributed Cache中,这里会对HashTableFiles进行压缩。

  2. MapReduce Job在Map阶段,每一个Mapper从Distributed Cache读取HashTableFiles到内存中,顺序扫描大表,在Map阶段直接进行Join,将数据传递给下一个MapReduce任务。

 conditionaltask

若是Join的两张表一张表是临时表,就会生成一个ConditionalTask,在运行期间判断是否使用MapJoin

CommonJoinResolver优化器

CommonJoinResolver优化器就是将CommonJoin转化为MapJoin,转化过程以下

  1. 深度优先遍历Task Tree
  2. 找到JoinOperator,判断左右表数据量大小
  3. 对与小表 + 大表 => MapJoinTask,对于小/大表 + 中间表 => ConditionalTask

遍历上一个阶段生成的MapReduce任务,发现MapReduceTask[Stage-2] JOIN[8]中有一张表为临时表,先对Stage-2进行深度拷贝(因为须要保留原始执行计划为Backup Plan,因此这里将执行计划拷贝了一份),生成一个MapJoinOperator替代JoinOperator,而后生成一个MapReduceLocalWork读取小表生成HashTableFiles上传至DistributedCache中。

 mapjoin变换

MapReduceTask通过变换后的执行计划以下图所示

 mapjoin变换

MapJoinResolver优化器

MapJoinResolver优化器遍历Task Tree,将全部有local work的MapReduceTask拆成两个Task

 MapJoinResolver

最终MapJoinResolver处理完以后,执行计划以下图所示

 MapJoinResolver

Hive SQL编译过程的设计

从上述整个SQL编译的过程,能够看出编译过程的设计有几个优势值得学习和借鉴

  • 使用Antlr开源软件定义语法规则,大大简化了词法和语法的编译解析过程,仅仅须要维护一份语法文件便可。
  • 总体思路很清晰,分阶段的设计使整个编译过程代码容易维护,使得后续各类优化器方便的以可插拔的方式开关,譬如Hive 0.13最新的特性Vectorization和对Tez引擎的支持都是可插拔的。
  • 每一个Operator只完成单一的功能,简化了整个MapReduce程序。

社区发展方向

Hive依然在迅速的发展中,为了提高Hive的性能,hortonworks公司主导的Stinger计划提出了一系列对Hive的改进,比较重要的改进有:

  • Vectorization - 使Hive从单行单行处理数据改成批量处理方式,大大提高了指令流水线和缓存的利用率
  • Hive on Tez - 将Hive底层的MapReduce计算框架替换为Tez计算框架。Tez不只能够支持多Reduce阶段的任务MRR,还能够一次性提交执行计划,于是能更好的分配资源。
  • Cost Based Optimizer - 使Hive可以自动选择最优的Join顺序,提升查询速度
  • Implement insert, update, and delete in Hive with full ACID support - 支持表按主键的增量更新

咱们也将跟进社区的发展,结合自身的业务须要,提高Hive型ETL流程的性能

参考

Antlr: http://www.antlr.org/
Wiki Antlr介绍: http://en.wikipedia.org/wiki/ANTLR
Hive Wiki: https://cwiki.apache.org/confluence/display/Hive/Home
HiveSQL编译过程: http://www.slideshare.net/recruitcojp/internal-hive
Join Optimization in Hive: Join Strategies in Hive from the 2011 Hadoop Summit (Liyin Tang, Namit Jain)
Hive Design Docs: https://cwiki.apache.org/confluence/display/Hive/DesignDocs

相关文章
相关标签/搜索