GROUP BY压缩行数生成聚合结果,PARTITION BY保留原始行数仅附加计算值;前者用于统计报表,后者用于明细分析并支持窗口函数排序、排名等操作。

GROUP BY 会压缩行数,PARTITION BY 不改变行数
这是最根本的区别。用 GROUP BY 后,结果集行数 ≤ 原始数据中分组键的去重数量;而 PARTITION BY 必须配合窗口函数(如 OVER())使用,它只是在原有每一行上“附加”计算值,原始行一条不少。
常见错误现象:SELECT name, salary, AVG(salary) FROM emp GROUP BY name 看似想查每个人工资和部门平均工资,实际会报错或逻辑错——因为 AVG(salary) 是聚合值,name 是分组键,但没说明怎么处理非分组非聚合字段(比如没写 salary 的聚合方式)。而换成 AVG(salary) OVER (PARTITION BY dept_id) 就合法,且每行都保留 name、salary、dept_id 全部明细。
-
GROUP BY后SELECT列只能是:分组字段本身,或带聚合函数的表达式 -
PARTITION BY出现在OVER()内,不参与 SQL 执行顺序中的分组阶段,而是在SELECT产出结果后才“叠加”计算 - 性能影响:大表上
GROUP BY通常触发哈希分组或排序,内存/磁盘开销明显;PARTITION BY在窗口计算阶段做分区扫描,若分区粒度粗(如全表一个分区),可能退化为全表遍历
PARTITION BY 必须和 OVER() 一起用,不能单独存在
PARTITION BY 不是独立语句,它只是 OVER() 子句的一个参数。脱离 OVER() 单独写 PARTITION BY 会直接报错,比如 SELECT * FROM t PARTITION BY col 是非法语法。
使用场景举例:想给每个部门员工按薪资倒序排号,同时保留所有字段:
SELECT emp_id, name, dept_id, salary,
ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rn
FROM employees;
这里 PARTITION BY dept_id 定义了“每个部门内部独立编号”,ORDER BY salary DESC 指定编号顺序,ROW_NUMBER() 是窗口函数本体。
- 漏写
OVER()是新手最常犯的语法错误,报错信息通常是 “missing window specification” 或类似提示 -
PARTITION BY可为空(即不写),此时整个结果集视为一个分区,例如COUNT(*) OVER()计算总行数 - 多个
PARTITION BY字段用逗号分隔,语义等同于多维分组,如PARTITION BY region, year
GROUP BY 的执行时机早于 PARTITION BY
SQL 标准执行顺序中,GROUP BY 发生在 HAVING 之前、SELECT 之后;而 PARTITION BY 所在的窗口函数,是在最终 SELECT 列确定后才计算的——也就是说,它看到的是已经过 GROUP BY 聚合后的那行数据(如果用了 GROUP BY 的话)。
这意味着:你不能在同一个查询里,既用 GROUP BY 压缩数据,又指望 PARTITION BY 对原始明细做分区计算。
- 想同时有部门汇总 + 员工明细?得用两个查询 union all,或用 CTE 分开处理
- 在
GROUP BY查询里嵌套窗口函数,PARTITION BY分的是聚合后的行,不是原始行。例如SELECT dept_id, COUNT(*) cnt, SUM(cnt) OVER (PARTITION BY dept_id)中,cnt是单个值,分区无意义 - Oracle/PostgreSQL 支持在
GROUP BY后再加窗口函数,但 MySQL 8.0+ 才完全支持该组合;旧版 MySQL 会报错
别把 PARTITION BY 当成 GROUP BY 的替代品
有人看到 PARTITION BY 也能“按某列分”,就试图用它绕过 GROUP BY 的字段限制,比如写 SELECT name, salary, AVG(salary) OVER (PARTITION BY dept_id) 来代替 GROUP BY dept_id。这能运行,但语义完全不同:前者返回所有员工记录,每人旁边附上其所在部门的平均工资;后者只返回每个部门一行,含部门 ID 和平均工资。
选择依据很简单:你要的是「报告」还是「标记」?
- 要生成统计报表、做数据聚合导出 → 用
GROUP BY - 要做排名、累计求和、前后行比较、保留明细的同时加统计列 → 用
PARTITION BY+ 窗口函数 - 两者混用时,务必确认数据库版本是否支持(尤其注意 MySQL 5.7 不支持窗口函数)
真正容易被忽略的是执行顺序带来的隐性依赖:当你在复杂查询里同时出现 WHERE、GROUP BY、WINDOW FUNCTION,PARTITION BY 看到的数据,已经是层层过滤和聚合后的结果——它不回溯原始表。










