窗口函数不能替代group by,因二者作用层级不同:group by聚合归并行集(输出行数≤输入),over保留原始行结构叠加计算(输出行数=输入);需压缩行数用group by,需每行附加统计值才用over。

不能,窗口函数和 GROUP BY 解决的是不同层级的问题:一个保留所有原始行,一个必须压缩行数。
为什么 GROUP BY 无法被窗口函数“绕过去”
当你只需要部门平均薪资列表(3 行),GROUP BY dept 直接输出 3 行;而 AVG(salary) OVER (PARTITION BY dept) 会返回 100 行,每行都带这个均值——多出来的 97 行不是冗余,是设计使然。想靠窗口函数“假装没分组”,结果只是把聚合值广播了一遍,并没真正归并数据。
-
GROUP BY是逻辑归并操作,执行后原始行不可见;窗口函数只在SELECT阶段计算,不改变行集结构 - 用
COUNT(*) OVER (PARTITION BY x)能知道每组几行,但没法直接生成“x, count”两列的结果集——你还得自己去重或再套一层 - 某些聚合(如
STRING_AGG、JSON_OBJECTAGG)没有对应的窗口版本,根本没法替代
PARTITION BY 不等于 GROUP BY,漏写就全错
这是最常踩的坑:AVG(salary) OVER () 和 AVG(salary) OVER (PARTITION BY dept) 看似只差几个字,结果天壤之别——前者是全表均值,后者才是按部门算。数据库不会报错,但业务逻辑已经崩了。
-
PARTITION BY是显式声明分组边界,不写就是默认整个结果集为一个分区 - 像
ROW_NUMBER() OVER (PARTITION BY user_id)在 PostgreSQL 中直接报错,MySQL 8.0 虽允许,但编号顺序无保证,两次查询结果可能不一致 -
ORDER BY在排名类函数中是强制项,在AVG/SUM中可省略,但一旦加上,语义就从“整组均值”变成“截至当前行的累计均值”
哪些场景下非得用 GROUP BY,窗口函数真干不了
只要目标是“减少行数”,窗口函数就无能为力。比如导出报表时要统计每个品类销售额+订单数+平均客单价,且只要一行一条品类——这种需求硬套窗口函数,就得先 GROUP BY 出中间结果,再用窗口函数加工,纯属画蛇添足。
- 需要哈希聚合加速(如大表按
region分组求和),GROUP BY可利用内存哈希,窗口函数通常要排序+扫描全分区 - 带
HAVING过滤分组结果(如“只看订单数 > 5 的用户”),窗口函数无法在计算后过滤分组,只能靠外层WHERE或子查询兜底 - 聚合字段参与后续
JOIN(如把部门汇总结果关联到组织架构表),GROUP BY输出是干净的二维结果,窗口函数输出仍是明细宽表,容易引发笛卡尔积
真正该纠结的不是“能不能替代”,而是“我要的是结果集变小,还是每行多一列”。选错就等于从根上写反了逻辑——尤其当 PARTITION BY 字段基数高(如百万级 user_id)、又没索引时,窗口函数性能可能比 GROUP BY 差一个数量级,还看不出错在哪。











