在 Hive 中,GROUP BY 和 DISTINCT 都可用于去重或聚合,但实现机制不同、适用场景不同、性能也不同。在大多数情况下,GROUP BY 的效率更高,尤其是在需要配合聚合函数或处理大数据量时。
✅ 一、核心区别
| 特性 | GROUP BY | DISTINCT |
|---|---|---|
| 用途 | 按字段分组,通常配合聚合函数(如 COUNT, SUM) | 对 SELECT 列整体去重 |
| 语法 | SELECT col1, COUNT(*) FROM t GROUP BY col1; | SELECT DISTINCT col1 FROM t; |
| 执行阶段 | 在 Reduce 阶段完成分组和聚合 | 本质是 GROUP BY 所有 SELECT 字段的简写 |
| 优化支持 | 支持倾斜优化(hive.groupby.skewindata)、向量化等 | 优化空间小,底层仍转为 GROUP BY |
🔍 关键事实:Hive 在底层会将
SELECT DISTINCT a, b自动转换为SELECT a, b FROM t GROUP BY a, b。
✅ 二、性能对比(为什么 GROUP BY 更高效?)
场景 1:仅去重(无聚合)
-- 写法1
SELECT DISTINCT user_id FROM logs;
-- 写法2
SELECT user_id FROM logs GROUP BY user_id;
✅ 两者执行计划几乎相同,性能接近。
但 GROUP BY 可额外开启优化:
SET hive.groupby.skewindata=true; -- 处理数据倾斜
而 DISTINCT 无法直接使用这些参数。
场景 2:去重 + 聚合(常见数仓场景)
-- 需求:统计每个用户的订单数(天然用 GROUP BY)
SELECT user_id, COUNT(order_id) FROM orders GROUP BY user_id;
-- 若强行用 DISTINCT(无法实现!)
-- ❌ 无法同时返回 user_id 和 count
✅ GROUP BY 是唯一选择,且可结合 Map 端预聚合优化:
SET hive.map.aggr=true; -- Mapper 先局部聚合,减少 Shuffle 数据量
场景 3:多列去重
SELECT DISTINCT dept, city FROM employees;
-- 等价于
SELECT dept, city FROM employees GROUP BY dept, city;
✅ 两者一样,但 GROUP BY 更清晰,且便于后续扩展(如加 HAVING)。
✅ 三、特殊注意:COUNT(DISTINCT) 性能陷阱!
-- 反模式:大表上直接 COUNT(DISTINCT)
SELECT COUNT(DISTINCT user_id) FROM huge_table;
⚠️ 问题:
- 所有
user_id都要发到 同一个 Reducer 去重(即使开启并行度也无效); - 极易导致 数据倾斜 + OOM + 超长运行时间。
✅ 优化方案:改写为 GROUP BY + COUNT
-- 两阶段聚合(推荐)
SELECT COUNT(*) FROM (
SELECT user_id FROM huge_table
GROUP BY user_id
) t;
- 第一阶段:多个 Reducer 并行去重;
- 第二阶段:汇总计数,避免单点瓶颈。
💡 Hive 3.0+ 对
COUNT(DISTINCT)有自动优化(近似或分阶段),但仍建议手动拆分。
📌 四、面试总结(一句话)
DISTINCT本质是GROUP BY的语法糖,在 Hive 中性能相当或略差;而GROUP BY更灵活、可优化、支持聚合,是生产环境的首选。尤其对于COUNT(DISTINCT),应主动改写为子查询 +GROUP BY避免性能灾难。
✅ 最佳实践建议
- 优先使用
GROUP BY,语义清晰且可控; - 避免直接
COUNT(DISTINCT big_column),改用两阶段聚合; - 开启优化参数:
SET hive.groupby.skewindata=true; -- 防倾斜 SET hive.map.aggr=true; -- Map 端预聚合

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



