partition by字段无索引会导致窗口函数卡顿,因数据库需全表扫描+磁盘排序定位分区边界;必须建立匹配的复合索引(如partition by a order by b对应索引(a,b)),否则执行计划中会出现sort method: external merge disk或windowagg耗时超80%。

PARTITION BY 字段没索引,窗口函数就容易卡在排序和分组上——这不是理论风险,而是执行计划里能直接看到的 Sort Method: external merge Disk 或 WindowAgg 节点耗时占比超 80% 的现实问题。
为什么数据库必须对 PARTITION BY 字段建索引
窗口函数本身不强制排序,但 PARTITION BY 触发的是“分组内上下文构建”,数据库要快速定位每个分区的起始/结束位置。没索引时,只能全表扫描 + 内存哈希或磁盘排序;有索引后,可直接跳转到 dept_id = 123 对应的数据块连续读取。
- 复合索引顺序必须匹配:如
PARTITION BY dept_id ORDER BY hire_date,索引得是(dept_id, hire_date),反过来无效 - 高基数分区键(如
user_id)更依赖索引——千万用户意味着千万个分区上下文,没索引就是千万次随机定位 -
EXPLAIN (ANALYZE)中若WindowAgg节点显示Partitions: 124567且Actual Total Time远高于其他节点,基本可断定是分区定位慢
ORDER BY 字段没索引时的真实表现
哪怕 PARTITION BY 字段有索引,只要 ORDER BY 字段没索引,照样会触发外部排序。比如 ROW_NUMBER() OVER (PARTITION BY region ORDER BY created_at DESC),created_at 若无索引,每个 region 分区内部都要单独做一次磁盘排序。
- MySQL 8.0+ 的
EXPLAIN FORMAT=TREE里出现filesort挂在 window function 下,就是这个信号 - PostgreSQL 中
Sort Method: external merge Disk占用大量Temp Buffers,说明排序已溢出内存 - 避免在表达式上排序:如
ORDER BY UPPER(name),普通索引无效,需额外建函数索引,且维护成本高
哪些 PARTITION BY 场景特别需要索引
不是所有 PARTITION BY 都同等危险,但以下组合一旦缺索引,性能恶化最明显:
- 分区键 + 排序键同时出现在
OVER()中,且数据量 > 10 万行 - 分区后存在严重倾斜,比如一个
tenant_id = 'legacy'分区占全表 70%,其余几百个租户各几百行——大分区排序完全无法并行摊薄 - 嵌套窗口:先按日期分区算累计值,再按地区重分区求排名,中间结果膨胀,没索引会让两层都变慢
- 在宽表上对未压缩列(如
TEXT、JSON)做分区,内存临时空间消耗翻倍,索引能减少物理读放大
真正卡住你的往往不是窗口函数语法,而是执行器找不到快速切分数据的路径。索引不是“锦上添花”,它是让 PARTITION BY 从 O(n²) 定位退化回 O(log n) 跳转的唯一确定性手段。











