MongoDB 3.6.3部分索引在count操作中未按预期工作求助
部分索引在MongoDB 3.6.3的count操作中未生效的排查与解决
我看你在MongoDB 3.6.3环境下创建了包含200万条记录的media集合,用的是这段批量插入代码:
function randInt(n) { return parseInt(Math.random()*n); } for(var j=0; j<20; j++) { print("Building op "+j); var bulkop=db.media.initializeOrderedBulkOp() ; for (var i = 0; i < 100000; ++i) { bulkop.insert( { id_profile: NumberLong("222"), needle_id: NumberInt(randInt(2000000000)), visibility: NumberInt(randInt(5)), } ); } print("Executing op "+j); bulkop.execute(); }
之后创建的部分索引在执行count时没达到预期效果,咱们来拆解下问题原因和解决办法:
核心前提:部分索引生效的条件
MongoDB的部分索引(Partial Index) 只有在你的count查询条件完全覆盖索引的过滤规则时,才会被用来优化查询。换句话说,如果你的count语句没带上部分索引定义里的partialFilterExpression条件,MongoDB会直接忽略这个索引,走全集合扫描。
举个例子:假设你创建的部分索引是这样的:
db.media.createIndex( { id_profile: 1 }, { partialFilterExpression: { visibility: { $gt: 0 } } } );
那只有当你执行包含过滤条件的count时,索引才会生效:
db.media.count({ id_profile: NumberLong("222"), visibility: { $gt: 0 } })
如果直接执行db.media.count({ id_profile: NumberLong("222") }),因为查询条件没匹配索引的过滤规则,MongoDB不会使用这个部分索引。
排查步骤
- 确认你的部分索引定义
执行db.media.getIndexes(),找到对应的部分索引,查看partialFilterExpression字段,明确索引的过滤条件是什么。 - 用explain分析执行计划
把你的count语句加上explain("executionStats")来查看执行细节:db.media.count({/* 你的查询条件 */}).explain("executionStats")- 如果看到
executionStats.executionStages.stage的值是COUNT_SCAN,说明索引被正常使用了; - 如果是
COLLSCAN,说明当前查询走的是全表扫描,索引没生效。
- 如果看到
- 检查MongoDB 3.6的版本限制
在3.6版本中,部分索引有这些使用限制:- 不支持搭配
$where、$text的查询; - 如果查询条件和索引的过滤条件冲突(比如索引过滤
visibility>0,但查询visibility=0),索引也不会被使用; - 无条件的全集合
count(db.media.count())也不会用到部分索引,因为需要统计所有文档。
- 不支持搭配
解决建议
- 如果你想让count用到部分索引,必须在查询中带上索引的过滤条件,确保查询逻辑和索引的过滤规则匹配;
- 如果需要对不满足部分索引过滤条件的文档也进行count优化,建议创建普通索引而非部分索引;
- 要是你本来就想统计符合部分索引过滤规则的文档数量,直接把过滤条件写进count语句即可,比如:
// 假设索引过滤条件是visibility < 5 db.media.count({ visibility: { $lt: 5 } })
内容的提问来源于stack exchange,提问作者zeus
相关产品推荐
相关产品推荐

