Hive执行计划之只有map阶段SQL性能分析和解读

打印 上一主题 下一主题

主题 652|帖子 652|积分 1956

目录

目录

概述

可能所有的SQLboy刚接触SQL语句的时候都是select xxx from xxx where xxx。在hive中,我们把这种语句称为select-from-where型语句,也可称为简单SQL,这类简单SQL是特指不含有变转换函数,聚合函数,开窗函数和连接操作的SQL语句。
这类SQL主要特征是只有map阶段,没有reduce阶段。
本文分析一下这类简单SQL执行计划和性能,让我们从最基础的SQL分析,hive简单语句select from where 型语句性能分析,逐渐深入,进而学会分析复杂SQL的性能和执行计划。
所有的复杂SQL(几百行?上千行?)都是由一个个简单SQL带一些特殊函数堆叠而成的。
1.不带函数操作的select-from-where型简单SQL

这类SQL语句通常只有select-from-where,没有其他函数操作,或者操作符处理,例如字符串截取。
1.1执行示例

例1 不带函数操作的select-from-where型简单SQL。
  1. -- 本文默认使用mr计算引擎
  2. explain
  3. -- 统计年龄等于30岁的所有昵称
  4. select age,nick from temp.user_info_all
  5. where ymd = '20230505'
  6. and age = 30;
复制代码
执行执行计划结果:
  1. STAGE DEPENDENCIES:
  2.   Stage-1 is a root stage
  3.   Stage-0 depends on stages: Stage-1
  4. STAGE PLANS:
  5.   Stage: Stage-1
  6.     Map Reduce
  7.       Map Operator Tree:
  8.           TableScan
  9.             alias: user_info_all
  10.             Statistics: Num rows: 32634295 Data size: 783223080 Basic stats: COMPLETE Column stats: NONE
  11.             Filter Operator
  12.               predicate: (age = 30) (type: boolean)
  13.               Statistics: Num rows: 16317147 Data size: 391611528 Basic stats: COMPLETE Column stats: NONE
  14.               Select Operator
  15.                 expressions: 30 (type: bigint), nick (type: string)
  16.                 outputColumnNames: _col0, _col1
  17.                 Statistics: Num rows: 16317147 Data size: 391611528 Basic stats: COMPLETE Column stats: NONE
  18.                 File Output Operator
  19.                   compressed: true
  20.                   Statistics: Num rows: 16317147 Data size: 391611528 Basic stats: COMPLETE Column stats: NONE
  21.                   table:
  22.                       input format: org.apache.hadoop.mapred.SequenceFileInputFormat
  23.                       output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
  24.                       serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
  25.   Stage: Stage-0
  26.     Fetch Operator
  27.       limit: -1
  28.       Processor Tree:
  29.         ListSink
复制代码
通过以上内容,我们可以看到,整个SQL逻辑执行过程中只有map操作树(Map Operate Tree),若转换成MapReduce来看的话,即只有Map阶段的任务。
如果有执行计划里关键词不熟悉的,建议阅读这篇 Hive执行计划之一文读懂Hive执行计划
1.2 运行逻辑分析

以上流程我们可以分解为运行逻辑图来看,如下图:

我们在之前的文章中提起过,Hive执行计划是一个预估的执行计划,只有在SQL实际执行后才会获取到真正的执行计划。那我们来看看以上语句的实际运行控制台打印过程。额,失算了,因为结果太多,限制一下输出条数。
  1. Query ID = hdfs_20230613111158_03c8f6e1-e04f-4e4e-aa9b-569a89860438
  2. Total jobs = 1
  3. Launching Job 1 out of 1
  4. # 这里表示没有reduce任务,reduce任务执行的服务器节点是0个。
  5. Number of reduce tasks is set to 0 since there's no reduce operator
  6. ...
  7. Hadoop job information for Stage-1: number of mappers: 6; number of reducers: 0
  8. 2023-06-13 11:12:28,564 Stage-1 map = 0%,  reduce = 0%
  9. 2023-06-13 11:12:45,219 Stage-1 map = 17%,  reduce = 0%, Cumulative CPU 6.17 sec
  10. ...
  11. 2023-06-13 11:12:54,523 Stage-1 map = 100%,  reduce = 0%, Cumulative CPU 40.52 sec
  12. MapReduce Total cumulative CPU time: 40 seconds 520 msec
  13. Ended Job = job_1675664438694_14052273
  14. MapReduce Jobs Launched:
  15. Stage-Stage-1: Map: 6   Cumulative CPU: 40.52 sec   HDFS Read: 203436481 HDFS Write: 2412 SUCCESS
  16. Total MapReduce CPU Time Spent: 40 seconds 520 msec
复制代码
从上面的结果可以知道,实际的运行过程也是只有map阶段的操作。
针对select-from-where只有map阶段操作而没有reduce阶段的主要原因是这类SQL只有从表中读取数据并执行数据行的过滤,并没有需要将HDFS在其他节点上的数据与该节点数据放在一起处理的必要,因此这类SQL不需要reduce操作。Map阶段过滤后的数据,就是最终的结果数据。
这种只含map的操作,如果文件大小控制在合适的情况下,都将只有本地操作,其执行非常高效,运行效率完全不输于在计算引擎Tez和Spark上运行。感兴趣的小伙伴可以去将三者运行效率比对一下。
1.3 伪代码解释

接下来我们再以mr伪代码的方式理解一下上述语句的运行情况:
例2 MRselect-from-where简单SQL代码解析
  1. map(inkey,invalue,context);
  2. colsArray = invalue.split("\t");
  3. //对应filter操作,过滤掉age=30的数据行,ymd为分区列,属于文件级操作,这里不展示了。
  4. if int(colsArray[11]) == 30 {
  5.   //获取age,nick两列,就是投影操作,即select操作
  6.   age = colsArray[11];
  7.   nick = colsArray[7];
  8.   //最后输出两列age,nick,执行计划中对应的为_col0和_col1.这里invalue为1
  9.   context.write(age,nick);
  10. }
  11. reduce(inkey,invalue,context)
  12.   //pass表示不会执行
  13.   pass;
复制代码
2.带普通函数和运行操作符的普通型SQL执行计划解读

这里的普通函数特指除表转换函数(UDTF),聚合函数和窗口函数之外的函数。例如:nvl(),cast(),case when,concat(),year()等,具体有哪些,后续会专门罗列。
这类SQL也属于select-from-where型SQL,其主要特点也是只有map阶段处理。
我们也可以给它更具体的称为 select-function(column)-from-where-function(column)类。
2.1 执行计划解读

接下来可以看一个带普通函数和操作符的SQL执行计划案例。
例3 带普通函数和操作符的SQL运行计划。
  1. explain
  2. -- 统计年龄等于30岁的所有昵称
  3. select uid,
  4. nvl(client,'android') as client,
  5. case when age > 20 then '老腊肉' else '小鲜肉' end as label,
  6. concat(nick,'_测试') as nick,
  7. cast(chat_uv as double)/10 as chat
  8. from temp.user_info_all
  9. where ymd = '20230505'
  10. and age in (18,19,20,21) and chat_uv is not null and substr(uid,0,1) = '1';
复制代码
输出的执行计划结果:
  1. STAGE DEPENDENCIES:
  2.   Stage-1 is a root stage
  3.   Stage-0 depends on stages: Stage-1
  4. STAGE PLANS:
  5.   Stage: Stage-1
  6.     Map Reduce
  7.       Map Operator Tree:
  8.           TableScan
  9.             alias: user_info_all
  10.             Statistics: Num rows: 32634295 Data size: 783223080 Basic stats: COMPLETE Column stats: NONE
  11.             # where 条件过滤
  12.             Filter Operator
  13.               predicate: ((age) IN (18, 19, 20, 21) and chat_uv is not null and (substr(uid, 0, 1) = '1')) (type: boolean)
  14.               Statistics: Num rows: 8158574 Data size: 195805776 Basic stats: COMPLETE Column stats: NONE
  15.               # 列投影
  16.               Select Operator
  17.                 expressions: uid (type: bigint), NVL(client,'android') (type: string), CASE WHEN ((age > 20)) THEN ('老腊肉') ELSE ('小鲜肉') END (type: string), concat(nick, '_测试') (type: string), (UDFToDouble(chat_uv) / 10) (type: double)
  18.                 outputColumnNames: _col0, _col1, _col2, _col3, _col4
  19.                 Statistics: Num rows: 8158574 Data size: 195805776 Basic stats: COMPLETE Column stats: NONE
  20.                 File Output Operator
  21.                   compressed: true
  22.                   Statistics: Num rows: 8158574 Data size: 195805776 Basic stats: COMPLETE Column stats: NONE
  23.                   table:
  24.                       input format: org.apache.hadoop.mapred.SequenceFileInputFormat
  25.                       output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
  26.                       serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
  27.   Stage: Stage-0
  28.     Fetch Operator
  29.       limit: -1
  30.       Processor Tree:
  31.         ListSink
复制代码
通过以上执行计划我们可以看到,这个结果同select-from-where 型SQL,只有map阶段的操作,如果实际去运行以上任务,得到的执行步骤也和例1类似。即在map运行完整个作业任务结束。
结合以上实例我们可以得出一个结论 select-function(colums)-from-where-function(column)这种类型的SQL可以归于select-from-where类简单SQL类型。
2.2 伪代码解释逻辑

例4 例2的MapReduce伪代码执行逻辑。
  1. //整个程序只有map阶段,没有reduce逻辑
  2. map(inkey,invalue,context);
  3. //数据输入是一行数据
  4. colsArray = invalue.split("\t");
  5. if age in (18,19,20,21) and chat_uv != null and substr(uid, 0, 1) == '1'{
  6.   uid = colsArray[0];
  7.   client = colsArray[3];
  8.   if client == null{
  9.     client = 'android';
  10.   }
  11.   label = '';
  12.   if age > 20 {
  13.     label = '老腊肉';
  14.   } else {
  15.     label = '小鲜肉';
  16.   }
  17.   nick = nick+'_测试');
  18.   chat = double(chat_uv)/10;
  19. }
  20. context.write(uid,client+'\t'+label+'\t'+nick+'\t'+chat);
复制代码
下一期:Hive常见时间函数的使用与问题整理
按例,欢迎点击此处关注我的个人公众号,交流更多知识。
后台回复关键字 hive,随机赠送一本鲁边备注版珍藏大数据书籍。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

水军大提督

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表