partition by 不适合报表统计,真正适合的是 group by;前者保留原始行数并附加分组计算值,后者压缩行数生成聚合摘要,如部门总人数、平均薪资等。

PARTITION BY 并不适合做“细粒度报表”——这个说法本身是个常见误解。真正适合报表统计(无论粗细粒度)的,是 GROUP BY;而 PARTITION BY 的作用根本不是生成报表,而是给已有明细行附加计算值。
误把窗口函数当报表工具,结果查出一堆重复行
典型错误现象:SELECT dept_id, name, salary, AVG(salary) OVER (PARTITION BY dept_id) —— 你想看“各部门平均薪资”,但实际得到的是每个员工一行,AVG(salary) 值在部门内完全重复。这不是报表,是冗余字段。
报表的本质是聚合压缩:你要的是“每个部门 1 行”,不是“每个员工 1 行 + 附带部门均值”。GROUP BY dept_id 才能自然产出这种结构。
-
GROUP BY后,SELECT dept_id, COUNT(*), AVG(salary)合法且结果行数 = 部门数 -
PARTITION BY必须嵌在OVER()里,它不改变行数,只叠加列 - BI 工具(如 Power BI、Tableau)直接对接
GROUP BY查询;对窗口函数结果需额外去重或再聚合,徒增逻辑风险
什么场景才真需要 PARTITION BY?
当你明确需要保留原始行,并在每行上加一个“分组内计算”的上下文字段时。PARTITION BY 不是报表方案,而是明细增强手段。
- 销售订单表加一列
rank_within_product:ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY amount DESC) - 用户日志加
session_seq:ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY event_time) - 股票行情加“5 日均价”:
AVG(close) OVER (PARTITION BY symbol ORDER BY date ROWS BETWEEN 4 PRECEDING AND CURRENT ROW)
这些操作输出仍是原始行数,只是每行多了一个动态计算字段——这和“报表”目标背道而驰。
GROUP BY 和 PARTITION BY 混用时的执行顺序陷阱
GROUP BY 在 WHERE 之后、SELECT 之前执行;PARTITION BY 所在的窗口函数,是在 SELECT 列确定后才计算的。
所以这个写法合法但无意义:SELECT dept_id, AVG(salary), COUNT(*) OVER (PARTITION BY dept_id)
-
GROUP BY dept_id已把 27 行员工压成 1 行/部门 -
COUNT(*) OVER (PARTITION BY dept_id)此时分区里只有 1 行,结果全是1 - 想统计“每个部门员工数”?直接用
COUNT(*)配合GROUP BY,别绕路
性能与可读性常被低估的细节
在大表上用 PARTITION BY 做“伪汇总”,实际开销可能比 GROUP BY 更高:
-
GROUP BY通常触发哈希分组,内存可控;PARTITION BY需维护每个分区状态,若分区键基数低(如PARTITION BY gender),可能退化为全表遍历 + 排序 - 看到
OVER (PARTITION BY ...)就该默认:这查询要保留明细。如果实际目标是报表,却写了窗口函数,后续维护者极易误判语义 -
PARTITION BY是逻辑分组,和建表时的PARTITION BY RANGE(存储层切分)完全无关,名字相同但机制不同,别混淆
真正容易被忽略的点:报表需求 ≠ 细粒度就该用窗口函数。粒度由业务决定(比如“按天汇总”或“按产品+地区汇总”),实现方式始终是 GROUP BY;而 PARTITION BY 只解决“怎么在不丢行的前提下,给每行打个分组标签”的问题。











