窗口函数本身不直接使用索引,但partition by和order by字段是否走索引直接决定性能;复合索引必须严格按partition by+order by顺序创建,rows模式可利用索引快速定位,range模式基本不能,join后窗口易失效,需通过子查询下推或物化中间结果优化。

窗口函数本身不直接使用索引,但 PARTITION BY 和 ORDER BY 字段是否走索引,直接决定查询是毫秒级还是分钟级——关键看执行计划里有没有 Using filesort 或 Using temporary。
复合索引必须严格匹配 PARTITION BY + ORDER BY 顺序
PostgreSQL 和 MySQL 都要求索引列顺序与 OVER() 子句中 PARTITION BY 后接 ORDER BY 的列顺序完全一致。比如:
- 查询写的是
OVER (PARTITION BY user_id, category ORDER BY created_at DESC)→ 索引必须是(user_id, category, created_at DESC) - 哪怕只调换
category和user_id位置,优化器大概率弃用该索引 -
INCLUDE可加非排序字段(如amount),避免回表,但不影响排序/分组逻辑
ROWS 模式能用索引,RANGE 模式基本不能
窗口帧(frame clause)类型极大影响索引有效性:
-
ROWS BETWEEN 10 PRECEDING AND CURRENT ROW:只要ORDER BY列有索引,就能用索引快速定位边界行,复杂度接近 O(1) 每行 -
RANGE BETWEEN INTERVAL '7 days' PRECEDING AND CURRENT ROW:即使ts有索引,也常退化为每行都做值范围扫描,无法跳过无关数据 -
ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW(累计求和)最友好,索引可支撑流式计算
JOIN 后的窗口函数容易失效,别信单表索引
MySQL 8.0+ 和部分 PostgreSQL 场景下,一旦窗口函数出现在多表 JOIN 结果集上,原有索引可能完全失效:
- 即使
orders表有(user_id, order_date)索引,JOIN customers后,ORDER BY order_date可能触发Using filesort - 原因:JOIN 改变了行物理顺序,优化器无法保证输出仍满足索引有序性
- 解决办法:先子查询过滤/排序再窗口,或在物化中间结果(如 CTE 加
MATERIALIZED)上建临时索引
真正卡住性能的往往不是函数本身,而是 PARTITION BY 字段没索引、ORDER BY 被函数包装(比如 DATE(created_at)),或者误以为 RANGE 也能走索引——这些细节不检查 EXPLAIN,光看 SQL 写法根本发现不了。










