Hive从入门到精通(九)调优

完整目录、平台简介、安装环境及版本:参考《Hive从入门到精通-概览》

九、调优

Hive会将HQL查询语言转换为MapReduce任务,大多数情况下,用户只需要专注手头的事情而不需要了解Hive内部是如何工作的。不过学习Hive背后的理论知识以及底层的一些细节会更有利于用户高效的使用Hive。

9.1 Explain

HiveQL是一种声明式语言,用户提交声明式的查询,而Hive会将其转换成MapReduce job。

使用EXPLAIN可以帮助我们学习Hive是如何将查询转换成MapReduce任务的。在查询语句前面加上explain关键字,可以看到查询计划和其它一些信息。但是这个查询本身是不会执行的。

一个Hive任务会包含一个或者多个stage(阶段),不同的stage会存在依赖关系。越复杂的查询会引入越多的stage,同样耗时也会越多。

一个stage可以是一个MapReduce任务,也可以是一个抽象阶段,或者一个合并阶段,还可以是一个limit阶段,以及Hive需要的其它某个任务的一个阶段。默认情况下,Hive会一次只执行一个stage,不过也可以并行执行。

Stage-1包含了大部分处理过程,而且还会触发一个MapReduce job。

map阶段–Map Operator Tree:TableScan以这个表作为输入,然后会产生一个字段amt_case的输出。Group By Operator会应用到sum(amt_case),然后产生一个输出字段_col0(临时字段)。

reduce阶段–Reduce Operator Tree:相同的Group By Operator,对_col0字段进行sum操作。File Output Operator说明输出结果是文本格式,是基于字符串的输出格式:HiveIgnoreKeyTextOutputFormat

Stage-0一般对应HQL的limit操作。

查询学生最高成绩,最低成绩,平均成绩:

命令:select max(score), min(score), avg(score) from stu_course;

使用explain查看执行过程:

命令:explain select max(score), min(score), avg(score) from stu_course;

Stage-1包含了大部分处理过程,而且还会触发一个MapReduce job。

map阶段–Map Operator Tree:TableScan以表data_query@stu_course作为输入,扫描整个表,然后会产生一个字段[“score”]的输出。Group By Operator会应用到[“max(VALUE._col0)”,”min(VALUE._col1)”,”sum(VALUE._col2)”,”count(VALUE._col3)”],然后产生一个输出字段[“_col0″,”_col1″,”_col2″,”_col3”] (临时字段)。

reduce阶段–Reduce Operator Tree:相同的Group By Operator,对[“_col0″,”_col1″,”_col2″,”_col3”]字段进行[“max(VALUE._col0)”,”min(VALUE._col1)”,”sum(VALUE._col2)”,”count(VALUE._col3)”]操作。File Output Operator说明输出结果是文本格式,是基于字符串的输出格式:HiveIgnoreKeyTextOutputFormat

Limit:-1是因为Job没有Limit语句,因此stage-0阶段是一个没有任何操作的阶段。

9.1.1 Explain extended

可以看到更多更详细的输出信息。

命令:explain extended select max(score), min(score), avg(score) from stu_course;

9.2 limit

很多情况下limit命令还需要执行整个查询语句,然后才返回部分结果,这种情况是非常浪费的,Hive可以通过配置进行控制。

将hive.limit.optimize.enable配置为true,同时限制搜索深度。

/hadoop/Hive/apache-hive-3.1.1-bin/conf/hive-site.xml

<property>
    <name>hive.limit.optimize.enable</name>
    <value>false</value>
    <description>Whether to enable to optimization to trying a smaller subset of data for simple LIMIT first.</description>
</property>
<property>
    <name>hive.limit.optimize.limit.file</name>
    <value>10</value>
    <description>When trying a smaller subset of data for simple LIMIT, maximum number of files we can sample.</description>
</property>
<name>hive.limit.row.max.size</name>
    <value>100000</value>
    <description>When trying a smaller subset of data for simple LIMIT, how much size we need to guarantee each row to have at least.</description>
</property>

查询语句加上limit:

命令:select max(score), min(score), avg(score) from stu_course limit 1;

使用explain查看:

命令:explain select max(score), min(score), avg(score) from stu_course limit 1;

9.3 join优化

由于Hive对每条记录进行连接操作时,会尝试将其他表缓存起来,然后扫描最后那个表进行计算,即假定最后那个表时最大的那个表,因此在连续查询时,表的大小从做到右一次增加。

如果使用过程中没有将最大表放在最后面,还可以通过标记将某个表强行指定为最后表。

式:SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON(c.key = b.key1)

a表被视为大表,则首先会对表b和c进行JOIN,然后再将得到的结果与表a进行JOIN。

比如查询学生学号,姓名,学校和成绩,需要用到三个表stu_basic 、stu_course和stu_school

hive> select stu_basic.no, name, school, score
    > from stu_basic join stu_course on(stu_basic.no=stu_course.no)
    > join stu_school on(stu_basic.no=stu_school.no);

其中stu_basic为最大表,强行将该表stu_basic指定为最后表

hive> select /*+STREAMTABLE(stu_basic)*/ stu_basic.no, name, school, score
    > from stu_basic join stu_course on(stu_basic.no=stu_course.no)
    > join stu_school on(stu_basic.no=stu_school.no);

9.4 并行执行

默认情况下,Hive一次只会执行一个阶段,有时候某些Job包含的多个阶段不是相互依赖的,可以并发执行,从而缩短正式时间,提高效率。通过设置配置文件中hive.exec.parallel为true即可。

/hadoop/Hive/apache-hive-3.1.1-bin/conf/hive-site.xml

<property>
    <name>hive.exec.parallel</name>
    <value>false</value>
    <description>Whether to execute jobs in parallel</description>
</property>

还存在很多其他的调优方式,就不一一介绍了。

发表回复