最根本差异是GROUP BY压缩行数而PARTITION BY不改变行数:前者按分组键聚合输出每组一行,后者配合OVER()为每行附加计算值且保留全部明细。

GROUP BY 会压缩行数,PARTITION BY 不改变行数
这是最根本的差异。用 GROUP BY 后,结果集行数 ≤ 分组键的去重数量;而 PARTITION BY 必须配合窗口函数(如 OVER())使用,它只是在每一行上“附加”计算值,原始行一条不少。
常见错误现象:SELECT name, salary, AVG(salary) FROM emp GROUP BY name 看似想查每个人工资和部门平均工资,实际会报错或逻辑错——因为 salary 既不是分组字段,也没套聚合函数。换成 AVG(salary) OVER (PARTITION BY dept_id) 就合法,且每行都保留全部明细字段。
- 要生成报表、统计每个部门总人数或平均薪资 → 用
GROUP BY - 要给销售订单加一列“本产品历史平均单价”,或给用户日志加“用户第几次访问” → 必须用
PARTITION BY配合窗口函数 -
GROUP BY后SELECT列只能是:分组字段本身,或带聚合函数的表达式
PARTITION BY 必须嵌在 OVER() 里,不能单独写
PARTITION BY 不是独立语法,它只是 OVER() 的一个参数。脱离 OVER() 单独写 PARTITION BY 会直接报错,比如 SELECT * FROM t PARTITION BY col 是非法语法。
正确结构只有一种:ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC)。漏写 OVER() 是新手最常犯的语法错误,报错信息通常是 “missing window specification” 或类似提示。
-
PARTITION BY可为空(即不写),此时整个结果集视为一个分区,例如COUNT(*) OVER()计算总行数 - 多字段分区写成
PARTITION BY region, year,语义等同于先按region再按year嵌套分组 -
GROUP BY是独立子句,出现在WHERE和HAVING之间;PARTITION BY所在的窗口函数,在SELECT输出后才计算
执行顺序和性能影响完全不同
GROUP BY 执行早于 SELECT,它看到的是原始行;而窗口函数(含 PARTITION BY)在 SELECT 产出结果后才叠加计算——也就是说,它能看到已经过 GROUP BY 聚合后的那行数据(如果用了 GROUP BY 的话)。
性能上:GROUP BY 在大表常触发哈希分组或排序,内存压力明显;PARTITION BY 是分区扫描,若分区键选择不当(比如用低基数字段),可能退化为全表遍历。
- MySQL 8.0+、PostgreSQL、SQL Server、Oracle、SQLite 3.25+ 全支持
ROW_NUMBER() OVER (PARTITION BY ...) -
GROUP BY执行计划关键词常见AGGREGATE或DERIVED;PARTITION BY对应关键词是WINDOW、SORT、PARTITION - 别把表级
PARTITION BY(建表时的存储分区)和窗口函数里的PARTITION BY搞混——同名不同源,前者是物理切分,后者是逻辑计算范围
最容易被忽略的一点:聚合函数在窗口内是逐行累积的
在 PARTITION BY 结果上使用聚合函数(如 MIN(salary) OVER (PARTITION BY dept_id ORDER BY hire_date)),该函数是逐条累计运行的,不是对整个分区一次性聚合。而 GROUP BY 后的聚合函数作用于分组下所有记录。
例如:MIN(salary) OVER (PARTITION BY dept_id ORDER BY hire_date ASC) 返回的是“截至当前行的最小值”,不是整个部门的全局最小值。要取全局值,得去掉 ORDER BY,写成 MIN(salary) OVER (PARTITION BY dept_id)。
这种行为差异直接影响排名、移动平均、累计求和等场景的逻辑准确性,但很容易被当成“和 GROUP BY 一样”。

















