本文转载自微信公众号《五分钟学大数据》,作者袁墨。转载本文请联系五分钟学大数据公众号。网上关于SQL语句执行顺序的资料很多,但是大部分都没有经过验证,而且很多都有小错误,尤其是select和groupby的执行顺序。有的说select先执行,有的说groupby先执行。两者中哪一个会先执行?今天我们就通过explain来验证SQL的执行顺序。在验证之前,先说一下结论。Hive中SQL语句的执行顺序如下:from..where..join..on..select..groupby..select..having..distinct..orderby..limit..union/unionall可以看到groupby在两个select之间。我们知道Hive默认在map端开启groupby分组,所以map端先执行select,reduce端先执行groupby。我们通过一条sql语句来分析一下:selectsum(b.order_amount)sum_amount,count(a.userkey)count_userfromuser_infoalftjoinuser_orderbona.idno=b.idnowherea.idno>'112233'groupbya.idnohavingcount_user>1limit10;上面的sql语句可以成功执行,我们看一下它在MR中的执行顺序:Map阶段:Executefrom,searchandloadtable;执行where,注意:在sql语句中,leftjoin写在where之前,但实际执行时先执行where操作,因为Hive会对语句进行优化,如果满足谓词下推规则,则谓词下推;执行leftjoin操作,根据key关联表;执行输出列操作,注意:select(order_amount,userkey)后只有两个字段,此时Hive是否只输出这两个字段,当然不是,因为groupby是idno,如果只有select的两个字段都是输出的,后面groupby就不能分组idno了,所以这时候输出的有三个字段:idno,order_amount,userkey;在map端执行groupby。此时分组方式采用hash分组,根据idno分组,进行order_amount的求和运算和userkey的count运算,最后根据idno进行排序(group默认会有排序操作);Reduce阶段:在reduce端执行groupby,此时的分组方式是合并并分组,根据idno对map端发送过来的数据进行分组合并,并在reduce端进行聚合操作sum(order_amount)同时计数(用户密钥);执行select,此时只输出select的两个字段:sum(order_amount)assum_amount,count(userkey)ascount_user;executehaving,此时才开始执行groupby过滤count_user后的having操作。注意:因为上一步输出的只是select的两个字段,所以having的过滤字段只能是这两个字段;executelimit限制输出行数为10上面的执行顺序对吗?我们可以通过explain执行计划看到。内容太多,分阶段来看。首先看sql语句的执行依赖关系:我们看到Stage-5是根,即Stage-5先执行,Stage-2依赖Stage-5,Stage-0依赖Stage-2。先执行Stage-5:图中标①为表扫描操作,注意先扫描b表,即leftjoin后的表,再进行过滤操作(图中标②)如图),我们的sql语句是针对a表过滤的,但是Hive会自动对b表进行同样的过滤操作,这样可以减少关联数据量。接下来执行Stage-2:首先是Map端的操作:先扫描表a(图中标记①);然后执行过滤操作idno>'112233'(图中标记②);然后进行leftjoin,关联的key为idno(图中标记③);执行关联操作后,会进行输出操作,输出为三个字段,包括两个select字段和一个groupby字段(图中标④);然后进行groupby操作,分组方式为hash(图中标注⑤);然后进行排序操作,根据idno进行正向排序(图中标记⑤)。然后是reduce端的操作:先进行groupby操作,注意此时的分组方式为mergepartial(图中①标示处);然后执行选择操作。此时只有两个输出字段,输出行数为30304行(图中标记②);接下来进行having的过滤操作,过滤掉count_user>1的字段,输出行数为10101行(图中标记③);然后执行limit,限制输出行数(图中标④);图中标记⑤表示是否压缩文件,false不压缩文件。执行计划中的数据量只是预测的数据量,并非实际运行,所以数据可能不准确!最后一个阶段是Stage-0:将最终输出行数限制为10行。总结基于以上对SQL执行计划的分析,总结出以下几点:每个stage都是一个独立的MR,复杂的hivesql语句可以生成多个stage。你可以通过执行计划的描述看到具体的步骤是什么。groupby的key必须是表中的字段,having的key必须是select的字段。orderby是在select之后执行的,所以orderby的key必须是select的字段。select最好指定字段,select*会增加很多不必要的消耗(CPU、IO、内存、网络带宽)。
