当前位置: 首页 > backend >正文

MySQL进阶实战:窗口函数 VS 聚合函数,性能与场景全对比


传统的聚合函数(Aggregate Functions)虽然功能强大,但在某些复杂分析场景下存在明显局限。自 MySQL 8.0 引入窗口函数(Window Functions)以来,SQL 语句的表达能力得到了极大扩展。

本篇文章将围绕“窗口函数 VS 聚合函数”展开全方位对比,从语法、执行原理、适用场景、性能分析、优化建议等多个角度进行深入解析,帮助你在实际开发中合理选择、更高效地编写 SQL 语句。


二、基础概念回顾

2.1 聚合函数简介

聚合函数是用于对一组值执行计算并返回单一值的函数,常见的有:

  • SUM():求和
  • COUNT():计数
  • AVG():平均值
  • MAX():最大值
  • MIN():最小值

通常与 GROUP BY 联合使用,例如:

SELECT department, AVG(salary)
FROM employees
GROUP BY department;

该语句将员工按部门分组,计算每个部门的平均工资。

2.2 窗口函数简介

窗口函数则是对查询结果中的每一行应用聚合计算,同时保留详细数据。它不会将结果按组折叠,而是保留原始行。典型语法结构为:

<窗口函数> OVER (PARTITION BY <分区列>ORDER BY <排序列>ROWS BETWEEN <窗口范围>
)

常见窗口函数包括:

  • ROW_NUMBER():行号
  • RANK() / DENSE_RANK():排名
  • SUM(), AVG(), MAX() 等聚合函数也可作为窗口函数使用

示例:

SELECT employee_id, department, salary,RANK() OVER (PARTITION BY department ORDER BY salary DESC) AS dept_rank
FROM employees;

此语句为每个部门内员工按工资从高到低排名。


三、语法与表达能力对比

功能对比项聚合函数 (Aggregate)窗口函数 (Window)
是否折叠数据
是否支持分区是(通过 GROUP BY是(PARTITION BY
是否支持排序否(需配合子查询/变量)是(ORDER BY
是否保留原始行数据否(每组输出 1 行)是(对每行应用计算)
是否支持滑动窗口是(通过 ROWS BETWEEN
典型使用场景汇总统计、图表聚合排名、环比、累计值、序列分析
MySQL版本支持所有版本8.0 及以上

聚合函数表达能力有限,窗口函数支持更复杂的数据分析需求。


四、典型场景对比

4.1 需求一:获取每个部门最高工资的员工信息

聚合函数写法(需子查询):

SELECT e.*
FROM employees e
JOIN (SELECT department_id, MAX(salary) AS max_salaryFROM employeesGROUP BY department_id
) m ON e.department_id = m.department_id AND e.salary = m.max_salary;

窗口函数写法(更直观):

SELECT *
FROM (SELECT *, RANK() OVER (PARTITION BY department_id ORDER BY salary DESC) AS rnkFROM employees
) t
WHERE rnk = 1;

4.2 需求二:统计员工工资的部门平均值,同时保留每条记录

聚合函数写法(需子查询或 JOIN):

SELECT e.*, d.avg_salary
FROM employees e
JOIN (SELECT department_id, AVG(salary) AS avg_salaryFROM employeesGROUP BY department_id
) d ON e.department_id = d.department_id;

窗口函数一行搞定:

SELECT *, AVG(salary) OVER (PARTITION BY department_id) AS avg_salary
FROM employees;

4.3 需求三:计算每个员工相对于部门的工资环比(前一行)

SELECT employee_id, department_id, salary,salary - LAG(salary) OVER (PARTITION BY department_id ORDER BY salary) AS salary_diff
FROM employees;

聚合函数无法实现这种按行滑动比较的需求,窗口函数是唯一选择。


五、性能对比实测

5.1 测试环境

  • MySQL 版本:8.0.36
  • 表结构:employees(约 100 万条记录)
  • 索引:department_id, salary
  • 硬件:8C/32G,SSD

5.2 测试案例

用例一:每个部门工资最高员工
  • 聚合 + JOIN:执行时间 ≈ 210ms
  • 窗口函数 + 子查询 + RANK:执行时间 ≈ 160ms
用例二:每位员工部门平均工资
  • 聚合 + JOIN:≈ 195ms
  • 窗口函数:≈ 140ms
用例三:员工工资同比增长
  • 聚合实现困难或需复杂子查询
  • 窗口函数:≈ 180ms

5.3 总结

在大量数据场景下,窗口函数通常具有更优的性能和更简洁的语法结构,尤其在不需要将数据折叠时效果更佳。


六、执行计划剖析与优化建议

6.1 执行计划观察方式

EXPLAIN FORMAT=JSON <SQL语句>;

重点关注字段:

  • using_temporary
  • using_filesort
  • window_functions
  • attached_conditions

6.2 窗口函数优化建议

  • 优化 PARTITION BYORDER BY 字段顺序,添加索引
  • 避免在窗口函数内部使用复杂表达式
  • 尽量减少窗口范围,必要时用 ROWS BETWEEN

6.3 聚合函数优化建议

  • GROUP BY 字段建立联合索引
  • ROLLUP 优化多级汇总
  • 考虑 HASH GROUP BY 替代 SORT GROUP BY

七、实战案例分享

案例一:用户留存率计算

需求:每天新增用户中,在接下来 7 天内是否登录过

SELECT user_id, register_date,MAX(CASE WHEN login_date BETWEEN register_date AND register_date + INTERVAL 7 DAY THEN 1 ELSE 0 END)OVER (PARTITION BY user_id) AS retained
FROM user_activity;

案例二:电商订单连续下单检测

SELECT user_id, order_date,DATEDIFF(order_date, LAG(order_date) OVER (PARTITION BY user_id ORDER BY order_date)) AS interval_days
FROM orders;

interval_days = 1,表示连续下单。

案例三:销售额累计趋势图

SELECT sale_date, region,SUM(sales_amount) OVER (PARTITION BY region ORDER BY sale_date) AS cumulative_sales
FROM sales;

使用窗口函数实现“累计和”非常直观。


八、何时使用窗口函数 VS 聚合函数?

聚合函数适用:

  • 需要折叠数据输出(如总和、计数)
  • 数据量小,逻辑简单
  • 查询可直接满足需求,无需保留明细

窗口函数适用:

  • 保留详细行数据
  • 涉及排序/排名、累计值、环比分析等
  • 避免嵌套子查询、逻辑清晰度优先

九、开发实战建议

场景/目的推荐函数说明
汇总报表聚合函数可读性强,执行高效
行内比较窗口函数LAG/LEAD 实现环比同比、连续天检测
排名类分析窗口函数RANK/DENSE_RANK
分类累计值计算窗口函数SUM() OVER + ORDER BY 实现趋势分析
同时使用多种聚合维度窗口函数更简洁避免 JOIN 或子查询

http://www.xdnf.cn/news/9154.html

相关文章:

  • Java 版本升级指南:从 Java 8 到 Java 11/17/21 的核心优势与新特性
  • ABAP Tools for Clean ABAP
  • dify-api的.env配置文件
  • 前端配置nginx代理
  • 预算超支、进度延误?工程企业如何实现精准管理?
  • 2025年储能产业TOP10省份及发展报告(附资料包下载)
  • 如何学习联邦学习和差分隐私
  • 家政维修平台实战10:搭建首页
  • 经典分类模型
  • 2021年江西工业互联网大赛———工业固件分析
  • 31.第二阶段x64游戏实战-封包-线程发包
  • 【科研绘图】3DMAX血管网络插件BloodVessels使用方法详解
  • 中级社会工作者《社会工作综合能力》的重点知识有哪些?
  • ASR/TTS model 通过量化提升推理速度
  • vue+ThreeJs 创造自动选择的甜甜圈(圆环)
  • 七彩喜认知症评估系统:解码大脑健康的“数字先知”
  • OpenGL Chan视频学习-7 Writing a Shader inOpenGL
  • 深度思考、弹性实施,业务流程自动化的实践指南
  • 网络编程学习笔记——TCP网络编程
  • 香港维尔利健康科技集团深化多方战略合作,构建全球智慧健康生态闭环
  • 2556. 第八大奇迹
  • OSPF补充信息
  • 亚马逊SP-API开发实战:商品数据获取与操作
  • 限流系列:resilience4j-ratelimiter
  • Linux环境下基于Docker安装 PostgreSQL数据库并配置 pgvector
  • [onnx 学习记录] 包包含的主要内容
  • Redisson分布式锁原理
  • 提升系统性能:Windows绿色版管理工具的实用指南
  • 红海云荣膺2025人力资源科技影响力品牌30强
  • IPD流程落地:项目任务书Charter开发