Hive性能调优
1.使用 EXPLAIN
学习 Hive 是如何工作的第一个步骤就是学习 EXPLAIN 功能,其可以帮助我们学习 Hive 是如何将查询转化成 MapReduce 任务的。
EXPLAIN SELECT SUM(number) FROM onecol;
首先,会打印出抽象语法树。它表明 Hive 是如何将查询解析成 token (符号) 和 literal (字面值) 的。
ABSTRACT SYNTAX TREE:
(TOK_QUERY
(TOK_FROM (TOK_TABREF (TOK_TABNAME onecol)))
(TOK_INSERT (TOK_DESTINATION (TOK_DIR TOK_TMP_FILE))
(TOK_SELECT
(TOK_SELEXPR
(TOK_FUNCTION sum (TOK_TABLE_OR_COL number))))))
我们可以忽略掉 TOK_ 这个前缀来查看输出信息。
尽管我们的查询会将其输出写入到控制台,但实际上会先将输出写入到一个临时文件中,正如下面输出信息中所表示的:
(TOK_INSERT (TOK_DESTINATION (TOK_DIR TOK_TMP_FILE))
一个 Hive 任务会包含有一个或多个 stage (阶段),不同的 stage 间会存在着依赖关系。越复杂的查询通常将会引入越多的 stage ,而通常 stage 越多就需要越多的时间来完成任务。
一个 stage 可以是一个 MapReduce 任务,也可以是一个抽样阶段,或者一个合并阶段,还可以是一个 limit 阶段,以及 Hive 需要的其他某个任务的一个阶段。默认情况下,Hive 会一次只执行一个 stage (阶段)。
2.EXPLAIN EXTENDED
使用 EXPLAIN EXTENDED 语句可以产生更多的输出信息。
3.限制调整
LIMIT 语句是大家经常使用到的。不过,在很多情况下,LIMIT 语句还是需要执行整个查询语句,然后再返回部分结果的。因为这种情况通常是浪费的,所以应该尽可能的避免出现这种情况。Hive 有一个配置属性可以开启,当使用 LIMIT 语句时,其可以对源数据进行抽样。
<property>
<name>hive.limit.optimize.enable</name>
<value>true</value>
<description>Whether to enable to optimization to
try a smaller subset of data for simple LIMIT first.</description>
</property>
一旦属性 hive.limit.optimize.enable 设置为 true ,那么还会有两个参数可以控制这个操作,也就是 hive.limit.row.max.size 和 hive.limit.optimize.limit.file 。
这个功能的一个缺点就是,有可能输入中有用的数据永远不会被处理到。
4.JOIN 优化
我们需要清楚哪个表是最大的,并将最大的表放置在 JOIN 语句的最右边,或者直接使用 /* streamtable(table_name) */ 语句指出。
如果所有表中有一个表足够的小,是可以完成载入到内存中的,那么这时 Hive 可以执行一个 map side join ,这样可以减少 reduce 过程,有时甚至可以减少某些 map task 任务。有时候即使某些表不适合载入内存也可以使用 map join ,因为减少 reduce 阶段可能比将不太大的表分发到每个 map task 中会带来更多的好处。
5.本地模式
大多数的 Hadoop Job 都是需要 Hadoop 提供的完整的可拓展性来处理大数据集的。不过,有时 Hive 的输入数据量是非常小的。在这种情况下,为查询触发执行任务的时间消耗可能会比实际 job 的执行时间要多得多,对于大多数这种情况,Hive 可以通过本地模式在单台机器上(或某些时候在单个进程中)处理所有的任务。对于小数据集,执行时间可以明显被缩短。
用户可以通过设置属性 hive.exec.mode.local.auto 的值为 true ,来让 Hive 在适当的时候启动这个优化。通常用户可以将这个配置写在 $HOME/.hiverc 。如果希望对所有的用户都使用这个配置,那么可以将这个配置项增加到 $HIVE_HOME/conf/hive-site.xml 文件中。
6.并行执行
Hive 会将一个查询转化成一个或者多个阶段。不过,某个特定的 job 可能包含众多的阶段,而这些阶段可能并非完全相互依赖,也就是说有些阶段是可以并执行的,这样可能使得整个 job 的执行时间缩短。不过,如果有更多的阶段可以并行执行,那么可能就越快完成。
通过设置 hive.exec.parallel 参数的值为 true ,就可以开启并发执行。不过,在共享集群中,需要注意,如果 job 中并行执行的阶段增多,那么集群利用率就会增加。
7.严格模式
Hive 提供了一个严格模式,可以防止用户执行那些可能产生意想不到的带来不好影响的查询。通过设置属性 hive.mapred.mode 的值为 strict ,可以禁止 3 种类型的查询。 (1)对于分区表,除非 WHERE 语句中含有分区字段过滤条件来限制数据范围,否则不允许执行。换句话说,就是用户不允许扫描所有分区。 (2)对于使用了 ORDER BY 语句的查询,要求必须使用 LIMIT 语句。 (3)限制笛卡尔积的查询。
SELECT * FROM fracture_act JOIN fracture_ads
WHERE fracture_act.planner_id = fracture_ads.planner_id;
FAILED: Error in semantic analysis: In strict mode, cartesian product is not allowed.
If you really want to perform the operation, +set hive.mapred.mode=nonstrict+
SELECT * FROM fracture_act JOIN fracture_ads
ON (fracture_act.planner_id = fracture_ads.planner_id);
8.调整 mapper 和 reducer 个数
Hive 通过将查询划分成一个或者多个 MapReduce 任务达到并行的目的。每个任务都可能具有多个 mapper 和 reducer 任务,其中至少有一些是可以并行执行的。确定最佳 mapper 个数和 reducer 个数取决于多个变量,例如输入的数据量大小以及对这些数据执行的操作类型等。
保持平衡性是有必要的。如果有太多的 mapper 或 reducer 任务,就会导致启动阶段、调度和运行过程中产生过多的开销;而如果设置的数量太少,那么就可能没有充分利用好集群内在的并行性。
当在共享集群上处理大任务时,为了控制资源利用情况,属性 hive.exec.reducers.max 显得非常重要。一个 Hadoop 集群可以提供的 map 和 reduce 资源个数(也称为插槽)是固定的。某个大 job 可能就会消耗完所有的插槽,从而导致其他 job 无法执行。通过设置属性 hive.exec.reducers.max 可以阻止某个查询消耗太多的资源。有必要将这个属性配置到 $HIVE_HOME/conf/hive-site.xml 文件中。
9.JVM 重用
JVM 重用是 Hadoop 调优参数的内容,其对 Hive 的性能具有非常大的影响,特别是对于很难避免小文件的场景或 task 特别多的场景,这类场景大多数执行时间都很短。
Hadoop 的默认配置通常是使用派生 JVM 来执行 map 和 reduce 任务的。这时 JVM 的启动过程可能会造成相当大的开销,尤其是执行的 job 包含成百上千个 task 任务的情况。JVM 重用可以使得 JVM 实例在同一个 job 中重新使用 N 次。N 的值可以在 Hadoop 的 mapred-site.xml 文件中(位于 $HADOOP_HOME/conf 目录下)进行设置。
10.索引
索引可以用来加快含有 GROUP BY 语句的查询的计算速度。
11.动态分区调整
动态分区 INSERT 语句可以通过简单的 SELECT 语句向分区表中创建很多新的分区。
这是一个强大的功能,不过如果分区的个数非常得多,那么就会在系统中产生大量的输出控制流。对于 Hadoop 来说,这种情况并不是常见的使用场景,因此,其通常会一次创建很多的文件,然后会向这些文件中写入大量的数据。
12.推测执行
推测执行是 Hadoop 中的一个功能,其可以触发执行一些重复的任务(task)。尽管这样会因对重复的数据进行计算,而导致消耗更多的计算资源,不过这个功能的目标是通过加快获取单个 task 的结果以及进行侦测,将执行慢的 TaskTracker 加入到黑名单的方式来提高整体的任务执行效率。
13.单个 MapReduce 中多个 GROUP BY
另一个优化是试图将查询中的多个 GROUP BY 操作组装到单个 MapReduce 任务中。如果想启动这个优化,那么需要一组常用的 GROUP BY 键。
14.虚拟列
Hive 提供了 2 种虚拟列:一种用于将要进行划分的输入文件名,另一种用于文件中的块内偏移量。
当 Hive 产生了非预期的或 null 的返回结果时,可以通过这些虚拟列诊断查询。通过查询这些字段,用户可以查看到哪个文件甚至是哪行数据导致出现的问题。
参考:《Hive 编程指南》
|