索引策略取决于查询中PARTITION BY字段是否参与WHERE/JOIN/ORDER BY,而非仅出现在PARTITION BY子句中;真正需建索引的场景是WHERE与PARTITION BY字段重叠,且ORDER BY字段必须包含在复合索引中并置于PARTITION BY字段之后。

PARTITION BY 字段本身不直接决定索引策略
SQL 的 PARTITION BY 是窗口函数(如 ROW_NUMBER()、RANK())的语法成分,它不改变表结构,也不自动创建物理分区或索引。很多人误以为“用了 PARTITION BY 就该给这些字段建索引”,其实不是——索引是否需要,取决于查询中这些字段如何被 WHERE、JOIN 或 ORDER BY 使用,而不是出现在 PARTITION BY 子句里。
真正该建索引的场景:WHERE + PARTITION BY 字段重叠
当你写类似这样的查询时,索引才起作用:
SELECT *, ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at) rn FROM orders WHERE user_id = 123;
这里 user_id 同时出现在 WHERE 和 PARTITION BY 中。数据库要快速定位 user_id = 123 的所有行,再按 created_at 排序——这时最有效的索引是:
-
(user_id, created_at)联合索引(顺序不能反) - 如果还有
ORDER BY或GROUP BY涉及其他字段,可扩展为(user_id, created_at, status) - 避免只对
user_id单独建索引,除非查询中它常被独立过滤
ORDER BY 字段比 PARTITION BY 字段更影响排序性能
窗口函数执行时,数据库必须对每个分区内的数据排序。即使 PARTITION BY user_id 把数据切开,若 ORDER BY created_at 没有对应索引,每个分区仍要临时排序,代价可能很高。
- 分区越小(如
user_id高基数),单个分区排序压力越低;但若user_id取值少(比如只有 10 个运营账号),一个分区可能含百万行,没索引就慢 -
ORDER BY字段必须包含在索引中,且位置要在PARTITION BY字段之后(例如(user_id, created_at)),才能被用于避免排序 - MySQL 8.0+、PostgreSQL、SQL Server 都支持用这类索引加速窗口函数,但 SQLite 不支持
分区表(Partitioned Table)和 PARTITION BY 完全无关
别混淆概念:PARTITION BY(窗口函数) ≠ 表级分区(如 MySQL 的 PARTITION BY RANGE 或 PostgreSQL 的 declarative partitioning)。后者是物理存储拆分,建索引规则不同:
- 表级分区上,通常需在每个子分区建本地索引,或建全局索引(取决于引擎支持)
- 而
PARTITION BY窗口函数不依赖表是否分区,它纯属逻辑计算 - 如果你真在用表级分区,又恰好按
user_id分区,那查询WHERE user_id = X可能触发分区裁剪——此时索引建在各子分区内部更有效
实际优化时,先看执行计划里的 Filter 和 Sort 节点耗时在哪,再决定索引字段和顺序。PARTITION BY 只是告诉你“这里要分组算”,不提供任何索引线索。

















