distribute by 是必须显式写出的 sql 子句,用于确保窗口函数正确分发数据;若漏写或字段顺序不匹配 partition by/order by,将退化为单 reducer 全局排序导致 oom。

DISTRIBUTE BY 不是配置项,而是必须显式写出的 SQL 子句;漏写或写错字段顺序,窗口函数会退化成单 reducer 全局排序,直接 OOM。
为什么 DISTRIBUTE BY 必须和 PARTITION BY + ORDER BY 对齐
窗口函数如 ROW_NUMBER() 在 Hive 中默认不自动推导分发逻辑。即使写了 PARTITION BY user_id ORDER BY event_time,若没加 DISTRIBUTE BY,所有数据仍 hash 到同一个 reducer —— 因为 Hive 无法保证不同 reducer 上的局部排序能拼出正确排名。
关键约束: DISTRIBUTE BY 字段必须是 ORDER BY 字段的最左前缀,且顺序严格一致。
- ✅ 正确:
DISTRIBUTE BY user_id ORDER BY user_id, event_time - ❌ 错误:
DISTRIBUTE BY event_time ORDER BY user_id, event_time(跨用户混排,rn=1可能出现在多个用户下) - ⚠️ 注意:
DISTRIBUTE BY (user_id, dt)合法,但ORDER BY必须以user_id, dt开头,比如ORDER BY user_id, dt, event_time
用 SORT BY 替代 ORDER BY 能省资源
当已用 DISTRIBUTE BY 把同 key 数据送入同一 reducer 后,ORDER BY 就成了冗余的全局强排序(强制 single reducer),而 SORT BY 只要求每个 reducer 内部有序,更轻量。
典型写法:
SELECT user_id, event_time, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY event_time) AS rn FROM logs DISTRIBUTE BY user_id SORT BY user_id, event_time;
这里 SORT BY 和 DISTRIBUTE BY 字段一致,既满足窗口排序前提,又避免了 ORDER BY 引发的 shuffle 瓶颈。
Hive 版本和引擎的隐性陷阱
旧版本 Hive(2.x)默认关闭 hive.optimize.sort.dynamic.partition,导致即使写了 DISTRIBUTE BY,窗口函数仍可能 fallback 到单 reducer。必须手动开启:
SET hive.optimize.sort.dynamic.partition=true;
使用 Tez 引擎时,CLUSTER BY(等价于 DISTRIBUTE BY + SORT BY)在窗口函数中行为不稳定,建议拆开写,避免不可预期的 ranking 断续。
如果 PARTITION BY 是 (user_id, dt),但 DISTRIBUTE BY 只写 user_id,部分 reducer 会收不到完整分区数据 —— 比如某天某个用户的数据被切到两个 reducer,rn 就会从 1 重复开始。
最容易被忽略的点:DISTRIBUTE BY 不生效的静默失败
它不会报错,也不会警告。你看到的结果“看起来对”,但实际是单 reducer 在跑,任务卡在 reduce 99%、内存溢出、或耗时陡增。验证方式只有两个:
- 查执行计划:
EXPLAIN EXTENDED看是否出现多个Reduce Operator Tree - 看 YARN 日志:确认 reducer 数量是否 > 1,且各 reducer 处理数据量相对均衡
别依赖 Hive 自动优化,尤其是嵌套子查询或带 CTE 的复杂窗口场景 —— 显式写 DISTRIBUTE BY 是唯一可控手段。










