窗口函数通过单次扫描完成分析计算,能大幅简化子查询结构并提升性能,尤其在排名、累计计算等场景15。以下是核心优化技巧:
一、排名场景替代方案
部门工资排名
传统子查询需自连接和聚合计数:sql
SELECT e1.name, e1.salary, (SELECT COUNT(*)+1 FROM employees e2 WHERE e2.dept=e1.dept AND e2.salary>e1.salary) AS rank FROM employees e1;
窗口函数单次扫描完成:
sql
SELECT name, salary, RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS rank FROM employees;
分组TOP N查询
使用ROW_NUMBER()
直接过滤组内前N条:sql
WITH ranked AS ( SELECT *, ROW_NUMBER() OVER (PARTITION BY dept ORDER BY sales DESC) AS rn FROM sales ) SELECT * FROM ranked WHERE rn <= 3;
避免关联子查询的多次索引扫描。
二、累计计算优化
- 子查询瓶颈:逐行执行导致O(n²)复杂度
sql
SELECT t1.date, (SELECT SUM(t2.amount) FROM sales t2 WHERE t2.date<=t1.date) AS cumulative FROM sales t1;
- 窗口方案:线性时间复杂度
sql
百万级数据性能提升显著。SELECT date, SUM(amount) OVER (ORDER BY date) AS cumulative FROM sales;
三、跨行引用优化
使用LAG()
避免自连接,例如环比增长率计算:
sql
SELECT month, revenue, (revenue - LAG(revenue,1) OVER (ORDER BY month)) / LAG(revenue,1) OVER (ORDER BY month) AS growth FROM financials;
比关联子查询减少50%以上I/O消耗。
四、关键优化原则
- 索引匹配
PARTITION BY
和ORDER BY
字段需建复合索引,否则全表扫描. - 框架选择
大分区数据用RANGE
替代ROWS
防内存溢出:sql
SUM(amount) OVER (ORDER BY date RANGE UNBOUNDED PRECEDING)
- 避免反模式
窗口函数中嵌套子查询会抵消性能优势.