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

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 或子查询

相关文章:

  • MyBatis 与 Spring 框架集成详解:构建企业级数据访问层
  • 泛型(1)
  • Elasticsearch实战:法律文档索引与管理的技术实践
  • Baklib的智能推荐系统核心是什么?
  • 【大模型】分词(Tokenization)
  • 【AI论文】LLaDA-V:具备视觉指令微调能力的大型语言扩散模型
  • Python基础教程:从零开始学习编程 - 第1-3天
  • 中国工程咨询协会新型基础设施专业委员会成立
  • C++:多重继承
  • 一些git的常见操作记录
  • 2556. 第八大奇迹
  • 机器学习-朴素贝叶斯分类
  • IP协议解析
  • RabbitMQ 集群与高可用方案设计(二)
  • 对数的运算困惑
  • C# Windows Forms应用程序-003
  • 数据洪流下,如何让数据库管理不再成为效率瓶颈?
  • 总结:进程和线程的联系和区别
  • 记录一个有用的tcpdump命令
  • Filter和Interceptor详解(一文了解执行阶段及其流程)
  • 电子配件 技术支持 东莞网站建设/互联网优化是什么意思
  • 网站备案 取消/广告软文200字
  • app开发与网站开发的区别/谷歌浏览器网址
  • 电子商务网站建设首要问题是/百度地图疫情实时动态
  • 沭阳各乡镇做网站/今天热搜前十名
  • wordpress导航图标代码/android优化大师