PARTITION BY 不能替代 GROUP BY,因前者保留原始行数并附加聚合值,后者压缩分组为单行;仅当需保留明细且计算跨行指标时才用 PARTITION BY。

PARTITION BY 不能替代 GROUP BY,这个前提必须先说清。如果你正试图用 PARTITION BY 去“实现报表汇总”,那大概率会写出冗余、低效、语义混乱的 SQL。
为什么 PARTITION BY 看起来像能“替代” GROUP BY?
因为两者都涉及“按某列分组”,但分组后的处理逻辑完全不同:
-
GROUP BY dept_id→ 把所有dept_id = 'd001'的 27 行压缩成 1 行,输出部门摘要 -
AVG(salary) OVER (PARTITION BY dept_id)→ 仍输出全部 27 行,每行多一列,值全是同一个平均数(重复 27 次)
这种“每行都带聚合结果”的表象,容易让人误以为它完成了 GROUP BY 的事——其实只是把结果复制粘贴了一遍,没做任何压缩或归约。
哪些场景下 PARTITION BY 确实能绕过 GROUP BY 的嵌套写法?
当你要保留原始明细,同时附加跨行计算时,PARTITION BY 是唯一合理选择,否则就得靠子查询 + JOIN 或应用层循环。典型例子:
- 给订单加一列
rank_within_product:ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY amount DESC) - 计算用户最近 3 次访问的平均停留时长:
AVG(duration) OVER (PARTITION BY user_id ORDER BY event_time ROWS BETWEEN 2 PRECEDING AND CURRENT ROW) - 标记每笔交易是否为该股票当日最高价:
CASE WHEN price = MAX(price) OVER (PARTITION BY symbol ORDER BY trade_time) THEN 1 ELSE 0 END
这些操作无法用 GROUP BY 直接表达,因为它们依赖行序、窗口偏移或逐行上下文,不是静态分组聚合。
混用 PARTITION BY 和 GROUP BY 时最容易踩的坑
语法上允许共存,但逻辑上极易出错:
-
SELECT dept_id, AVG(salary), COUNT(*) OVER (PARTITION BY dept_id)——COUNT(*)统计的是GROUP BY后每组的 1 行,结果全是1,毫无意义 -
ORDER BY在窗口函数里缺位:漏写ORDER BY会导致ROW_NUMBER()无序编号,SUM() OVER (PARTITION BY x)变成全组静态和(失去累计/移动语义) - 分区键基数太低(如
PARTITION BY gender):引擎可能放弃分区优化,退化为全表扫描 + 排序,比GROUP BY更慢
更隐蔽的问题是可读性:看到 OVER (PARTITION BY ...) 就默认“这行要留着”,如果实际目标是出报表,却写了窗口函数,后续维护者第一反应不是“这里算得对不对”,而是“这里是不是漏了 GROUP BY”。
真正该用 GROUP BY 还是 PARTITION BY?只看这一条
问自己:最终结果集的行数,是否允许变化?
- 要输出“每个部门一行,含总人数、平均薪资” → 必须用
GROUP BY - 要输出“每个员工一行,额外带‘本部门薪资排名’” → 必须用
PARTITION BY
别被“分组”这个词带偏。PARTITION BY 不是分组的另一种写法,它是开窗的坐标系;GROUP BY 是降维的手术刀。用错地方,不是少写个括号的事,是整个分析逻辑的起点就错了。

















