mysql 8.0未新增聚合函数,而是支持其窗口化使用;通过sum() over()、avg() over()等实现一次扫描完成累计、移动平均等计算,避免多层子查询与自连接,显著提升报表性能。

MySQL 8.0 并没有新增“聚合函数”本身,而是让原有聚合函数(如 SUM、AVG、COUNT、MIN、MAX)支持窗口化使用——这才是报表分析提速的关键。 直接在 GROUP BY 里套用这些函数,和把它们放进 OVER() 里,效果天差地别。
为什么传统聚合函数在报表里越来越吃力
当你需要“每个销售员的销售额,同时显示其所在区域的平均销售额、累计销售额、排名、同比变化”,传统写法只能靠多层子查询或自连接。数据量一过百万行,执行计划容易崩,临时表膨胀,IO飙升。
典型卡点包括:
-
GROUP BY后无法保留明细行,必须再JOIN回原表,索引失效风险高 - 计算环比/移动平均时,硬写
LEFT JOIN或变量模拟,逻辑难维护、并发下易出错 - 多个聚合维度(比如按月+按地区+按产品线)嵌套时,
GROUP BY组合爆炸,SQL 膨胀且难调试
SUM() OVER() 和 AVG() OVER() 怎么改写报表逻辑
核心是:把“先分组再汇总”变成“边扫描边计算”,一次全表扫描完成所有窗口指标。
例如统计各区域销售员的累计业绩(按时间排序):
SELECT
region,
salesperson,
sale_date,
amount,
SUM(amount) OVER (
PARTITION BY region
ORDER BY sale_date
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
) AS cum_amount,
AVG(amount) OVER (
PARTITION BY region
ORDER BY sale_date
ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING
) AS moving_avg_3d
FROM sales;
关键点:
-
PARTITION BY region替代了GROUP BY region,但不丢行 -
ROWS BETWEEN ...显式控制计算范围,比模糊的“上一行”更可控 - 两个窗口函数共用同一扫描,不额外触发二次读取
容易被忽略的性能陷阱
窗口函数不是银弹,滥用反而拖慢查询:
- 没加
ORDER BY的OVER()(如SUM(amount) OVER(PARTITION BY region))会强制对每个分区做全排序,大数据量下极慢 -
RANGE框架(如RANGE BETWEEN INTERVAL '30' DAY PRECEDING AND CURRENT ROW)在时间字段无索引时,可能退化为全分区扫描 - 在
WHERE过滤前就执行窗口计算——务必确认执行计划中WHERE是否下推到了窗口之前 -
FIRST_VALUE/LAST_VALUE默认行为依赖FRAME,不显式声明ROWS或RANGE容易返回意料外结果
真正提升报表效率的,不是函数多了几个,而是你能否用好 OVER() 里的 PARTITION BY、ORDER BY 和框架定义——它们共同决定了 MySQL 是扫一遍还是扫十遍。











