订阅更新

一条Hive SQL从提交到出结果,到底经历了什么?

Hive手册 第 1 题 约 3 分钟读完

本文目录
  1. 先说结论
  2. 业务场景:一条广告报表SQL的执行过程
  3. 面试高频追问:现在还有人用MapReduce作为执行引擎吗?
  4. 实战踩坑:分区裁剪失效的教训
  5. 总结

先说结论

一条Hive SQL从提交到出结果,经历六个阶段:

① 词法/语法解析: 把SQL字符串解析成抽象语法树(AST),检查语法是否正确。

② 语义分析: 检查表名、列名是否存在,数据类型是否匹配。这一步会查询MetaStore。

③ 逻辑计划生成: 把AST转换成由算子组成的逻辑执行计划(过滤、分组、Join等)。

④ 逻辑计划优化: 谓词下推、列裁剪、分区裁剪、Map端聚合等优化。这是性能的关键。

⑤ 物理计划生成: 把逻辑计划转换成可执行的MapReduce/Tez/Spark作业。

⑥ 提交执行: 把作业提交到YARN上执行,监控进度,收集结果。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

这道题是Hive面试的“开局王炸”,几乎每场必问。但很多人的回答停留在“解析SQL→生成MapReduce→执行”这个粗糙的层面,再往下追问就卡住了。今天我用一条真实的生产SQL来把整个执行过程走一遍。

业务场景:一条广告报表SQL的执行过程

假设我在短剧出海公司要查昨天各渠道的广告ROI:

SELECT
  a.channel,
  SUM(a.cost) AS total_cost,
  SUM(r.revenue) AS total_revenue,
  SUM(r.revenue) / SUM(a.cost) AS roi
FROM ad_cost a
JOIN revenue r ON a.ad_id = r.ad_id
WHERE a.dt = '2025-03-14'
GROUP BY a.channel;

这条SQL在Hive里实际会发生什么?

1. Hive先解析SQL,发现要做Join + GroupBy,至少需要两个MapReduce作业(如果用Tez则可能合并为一个DAG)。

2. 优化器发现dt='2025-03-14'是分区过滤条件,只读取该分区的数据(分区裁剪)。如果没有这个优化,就会扫描全部历史数据,慢几十倍。

3. 优化器还会做列裁剪——ad_cost表可能有20个字段,但只读取channel、ad_id、cost、dt。

4. 生成MapReduce作业提交到YARN执行,最终结果写入临时目录。

面试高频追问:现在还有人用MapReduce作为执行引擎吗?

这个问题能展示你对技术演进的了解。

MapReduce: 古老的执行引擎,每个MR作业之间要落盘,多个MR作业串行执行,非常慢。现在基本没人用了。

Tez: 把多个MR作业合并成一个DAG,中间结果不落盘,快很多。Hive 2.x默认引擎。

Spark: 现在的主流选择。我待过的四家公司,新项目全部用Spark作为Hive的执行引擎。

实战踩坑:分区裁剪失效的教训

我在元宇宙社交App那家公司遇到过一个典型的坑:有个同事写SQL时把分区字段放在了一个函数里:

-- ✖ 这样写分区裁剪失效!
WHERE DATE_FORMAT(dt, 'yyyy-MM') = '2025-03'
 
-- ✔ 应该这样写
WHERE dt >= '2025-03-01' AND dt < '2025-04-01'

第一种写法对dt字段做了函数转换,优化器认不出这是分区过滤,直接扫描全表。这个作业原本只需要3分钟,结果跑了40分钟。

所以分区字段一定要“裸用”,不要包在任何函数里。这个细节面试里说出来,绝对加分。

总结

记住六个阶段:解析→语义→逻辑计划→优化→物理计划→执行。重点掌握优化阶段的分区裁剪、列裁剪、谓词下推。面试的时候用一条真实的SQL来举例子,比干巴巴列步骤有说服力得多。

下一篇聊一个非常实用的场景题:一张千亿级的用户行为日志表,你怎么设计分区和分桶?这道题能看出你有没有真正建过表。

你们生产环境Hive的执行引擎是什么?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器