Hive 的执行计划比传统数据库更复杂,因为它将 SQL 翻译成多阶段的 MapReduce、Tez 或 Spark 任务。
Hive 提供了两种类型的执行计划,用于不同阶段的优化和分析:
- 抽象语法树 (AST):SQL -> 抽象语法树的转换。
- 查询执行计划 (Query Execution Plan):这是我们性能调优最关心的部分,它展示了 Hive 如何将查询转换为底层计算框架(如 MR/Tez/Spark)的任务。它又分为两个阶段:
- Stage 1: Logical Plan (逻辑执行计划):由多个逻辑操作符组成的算子树。
- Stage 2: Physical Plan (物理执行计划):将逻辑操作符优化、切分后,生成的具体物理执行步骤,最终会转换为 MR/Tez/Spark 的 DAG(有向无环图)。
1. 如何查看执行计划?
主要通过 EXPLAIN 和 EXPLAIN EXTENDED 命令来查看。
基础语法:EXPLAIN
EXPLAIN [FORMATTED|EXTENDED|DEPENDENCY|AUTHORIZATION|...]
your_sql_statement;
最常用的选项是 FORMATTED 和 EXTENDED。
示例:查看一个简单查询的执行计划
-- 先设置显示表头,方便阅读(可选)
set hive.cli.print.header=true;
-- 1. 基础EXPLAIN
EXPLAIN
SELECT deptno, AVG(sal) AS avg_sal
FROM emp
WHERE sal > 1000
GROUP BY deptno
HAVING avg_sal > 2000;
-- 2. 查看更详细的计划(推荐使用)
EXPLAIN FORMATTED
SELECT deptno, AVG(sal) AS avg_sal
FROM emp
WHERE sal > 1000
GROUP BY deptno
HAVING avg_sal > 2000;
-- 3. 查看最最详细的计划(信息量巨大)
EXPLAIN EXTENDED
SELECT deptno, AVG(sal) AS avg_sal
FROM emp
WHERE sal > 1000
GROUP BY deptno
HAVING avg_sal > 2000;
2. 执行计划结果解读(核心)
我们以 EXPLAIN FORMATTED 的输出为例进行解读。输出内容非常结构化,主要包含以下几个部分:
第一部分:STAGE DEPENDENCIES (阶段依赖)
这部分展示了所有执行阶段的依赖关系,即执行的先后顺序。
STAGE DEPENDENCIES:
Stage-1 is a root stage
Stage-0 depends on stages: Stage-1
- 解读:这表示这个查询有两个阶段:
Stage-1和Stage-0。 Stage-1是根阶段,最先执行。Stage-0是一个后续阶段,它依赖于Stage-1的执行结果(通常是做最终的聚合、排序或限制输出)。
这是理解任务并行度和执行流程的第一步。
第二部分:STAGE PLANS (阶段计划)
这是执行计划的核心,详细描述了每个 Stage 要做什么。 我们会看到类似以下的结构:
STAGE PLANS:
Stage: Stage-1
Map Reduce
Map Operator Tree:
TableScan // 扫描表
alias: emp
Statistics: Num rows: 1 Data size: 1000 Basic stats: COMPLETE Column stats: NONE
Filter Operator // 过滤操作 (对应WHERE子句)
predicate: (sal > 1000) (type: boolean)
Statistics: Num rows: 1 Data size: 500 Basic stats: COMPLETE Column stats: NONE
Select Operator // 选择列操作
expressions: sal (type: double), deptno (type: int)
outputColumnNames: sal, deptno
Statistics: Num rows: 1 Data size: 500 Basic stats: COMPLETE Column stats: NONE
Group By Operator // 分组聚合操作 (对应GROUP BY)
aggregations: avg(sal)
keys: deptno (type: int)
mode: hash
outputColumnNames: _col0, _col1
Statistics: Num rows: 1 Data size: 500 Basic stats: COMPLETE Column stats: NONE
Reduce Output Operator // Map端的输出,准备发给Reduce
key expressions: _col0 (type: int)
sort order: +
Map-reduce partition columns: _col0 (type: int)
Statistics: Num rows: 1 Data size: 500 Basic stats: COMPLETE Column stats: NONE
value expressions: _col1 (type: double)
Reduce Operator Tree:
Group By Operator // Reduce端的分组聚合
aggregations: avg(VALUE._col0)
keys: KEY._col0
mode: mergepartial
outputColumnNames: _col0, _col1
Statistics: Num rows: 1 Data size: 500 Basic stats: COMPLETE Column stats: NONE
Filter Operator // 过滤操作 (对应HAVING子句)
predicate: (_col1 > 2000.0) (type: boolean)
Statistics: Num rows: 1 Data size: 500 Basic stats: COMPLETE Column stats: NONE
File Output Operator // 输出结果
compressed: false
Statistics: Num rows: 1 Data size: 500 Basic stats: COMPLETE Column stats: NONE
table:
input format: org.apache.hadoop.mapred.SequenceFileInputFormat
output format: org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat
serde: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
Stage: Stage-0
Fetch Operator
limit: -1
Processor Tree:
ListSink
关键操作符 (Operator) 解读:
| 操作符 (Operator) | 描述 | 解读与优化点 |
|---|---|---|
TableScan | 表扫描 | 读取数据源。关注 alias(表名)和 Statistics(统计信息)。 |
Filter Operator | 过滤 | 对应 WHERE 和 HAVING 子句。查看 predicate 了解过滤条件。尽早过滤数据能大幅减少后续处理的数据量。 |
Select Operator | 列投影 | 选择需要输出的列。查看 expressions 和 outputColumnNames。只选择必要的列,避免 SELECT *。 |
Group By Operator | 分组聚合 | 对应 GROUP BY。注意 mode:- hash:在 Map 端进行部分聚合,极佳优化。 - mergepartial:在 Reduce 端合并 Map 端的部分聚合结果。 - complete:完全聚合。 |
Reduce Output Operator | Map 端输出 | 决定 Map 端输出如何分区、排序给 Reduce 端。关注 key expressions(分区/排序键)和 Map-reduce partition columns。这关系到数据倾斜。 |
Join Operator | 表连接 | (本例未出现)最常见的性能瓶颈。重点关注连接类型和大小表顺序。 |
File Output Operator | 结果输出 | 写出最终结果。 |
Statistics | 统计信息 | 极其重要! 包含 Num rows(行数)和 Data size(数据大小)的预估。如果显示 Column stats: NONE,说明缺少列统计信息,可能导致优化器生成劣质计划。需运行 ANALYZE TABLE 收集统计信息。 |
3. 核心性能调优关注点
当您查看 Hive 执行计划时,请带着以下问题去分析:
-
数据流是否高效?
- 查看
STAGE DEPENDENCIES,阶段是否过多?能否合并? - 警惕
Cartesian Product(笛卡尔积),这通常是性能灾难。
- 查看
-
是否有数据倾斜 (Data Skew) 风险?
- 查看
Group By Operator和Reduce Output Operator的key。如果某个 key 的值特别多,会导致单个 Reduce 任务处理大量数据,远慢于其他任务。 - 优化方案:使用
set hive.groupby.skewindata=true;或手动处理倾斜 key。
- 查看
-
统计信息是否准确?
- 检查每个
Operator下的Statistics。如果一直是Num rows: 1或Data size: xxx,说明优化器在瞎猜,计划很可能不是最优的。 - 优化方案:对表和相关列收集统计信息:
ANALYZE TABLE emp COMPUTE STATISTICS;和ANALYZE TABLE emp COMPUTE STATISTICS FOR COLUMNS sal, deptno;。
- 检查每个
-
是否用上了分区和分桶?
- 在
TableScan中,如果表有分区,应该能看到分区过滤条件,例如partition predicate: (month=202405)。避免全表扫描。
- 在
-
连接 (JOIN) 操作是否高效?
- 确保大表在最后(对于旧版 MapReduce Join)或使用 MapJoin(对于小表)。
- 查看计划中是否有
Map Join Operator,这表示小表被加载到内存中,效率极高。如果没有,可以尝试提示:SELECT /*+ MAPJOIN(small_table) */ ...或设置set hive.auto.convert.join=true;。
总结
- 命令:使用
EXPLAIN FORMATTED获取最清晰易读的计划。 - 步骤:先看
STAGE DEPENDENCIES了解阶段流程,再深入STAGE PLANS分析每个操作符的细节。 - 核心:重点关注
Statistics(统计信息)、Filter(过滤时机)、Group By的mode、Join的类型以及Reduce Output的 key(数据倾斜)。 - 优化:根据计划反馈的问题,采取相应措施:收集统计信息、避免笛卡尔积、处理数据倾斜、利用分区剪裁、启用 MapJoin 等。
熟练阅读 Hive 执行计划是从“会用 Hive”到“精通 Hive 调优”的关键一步。
7434

被折叠的 条评论
为什么被折叠?



