MongoDB 的 setIndexFilter 是强制索引绑定机制,按 query shape 精确匹配并固定使用指定索引,仅对 find/count/distinct 有效,不依赖 Plan Cache,且不自动退化;匹配要求字段名、操作符、嵌套路径等完全一致。

不能通过“索引合并”来固定执行计划——MongoDB 不支持传统意义上的索引合并(Index Merge),所谓“Index Filter”也不是合并多个索引,而是为特定查询形态硬编码指定唯一可用索引。
db.runCommand({setIndexFilter: ...}) 是什么操作
这是 MongoDB 提供的强制索引绑定机制,作用对象是 query shape(即规范化后的查询条件结构),不是某条具体语句。它不依赖 Plan Cache,也不随数据分布变化而失效,只要 query shape 完全匹配,就强制使用你指定的索引组合。
- 必须显式调用
db.runCommand({setIndexFilter: ...})才生效,不会自动触发 - 只对
find、count、distinct有效,aggregate或updateMany不受约束 - 如果
indexes数组中列出的索引在当前集合上不存在,或无法支撑该 query shape(比如缺等值字段),MongoDB 直接报错"no matching index",不会退回到默认行为 - 验证是否生效:执行
db.collection.find(...).explain("executionStats"),检查queryPlanner.indexFilterSet是否为true,且executionStats.executionStages.stage是IXSCAN而非COLLSCAN
query shape 匹配有多严格
它不是模糊匹配,而是字段名、嵌套路径、操作符类型、甚至键顺序都必须一致。例如 {"Tags.SN": "QZ435698245"} 和 {"Tags.SN": {"$eq": "QZ435698245"}} 就是两个不同 shape,后者不会命中前者设置的 filter。
- 大小写敏感:
"tags.sn"≠"Tags.SN" - 不包含
sort、projection、limit等选项,这些不影响 shape 判定 - 数组查询需注意:若字段是数组,
{"arr": 1}和{"arr": {"$in": [1]}}视为不同 shape - 通配无效:不能用
{"Tags.SN": /QZ.*/}去匹配所有 SN 查询,每个正则 pattern 都要单独设 filter
为什么 setIndexFilter 比 clearPlanCache 更可靠
因为 Plan Cache 是动态学习结果,容易被首次参数偏差、数据分布迁移、主备切换等干扰;而 Index Filter 是静态指令,只要 query shape 不变,它就永远强制走你指定的索引。
-
clearPlanCache只清空缓存,下次执行仍可能选错——尤其当首次运行参数恰好是长尾值时 - Index Filter 不会被
replanning覆盖,也不会因新建/删除其他索引而自动失效 - 但它也更重:一旦设错,所有匹配查询都会失败;删掉要用
db.runCommand({deleteIndexFilter: ...}),没有“禁用开关” - 多个相似但不完全相同的 query shape(如不同 status 值、不同正则 pattern),必须分别设置,不能复用
真正容易被忽略的是:Index Filter 不解决“该用哪个索引”的问题,它只解决“用了这个索引后别换”的问题。如果你指定的索引本身不适合该 query shape(比如漏了排序字段导致内存排序),filter 生效反而会固化性能缺陷。











