MongoDB 官方文档指出,所谓覆盖查询(Covered Query)通常需要满足以下条件:

- 所有查询条件字段都属于索引的一部分
- 所有需要返回的字段也都包含在同一个索引中
由于查询过程中涉及的全部字段都已经存储在索引里,因此 MongoDB 无需再次回表扫描完整文档;它可以直接依靠索引完成条件过滤,并返回同样来自该索引中的查询结果。
因为索引通常会被加载到 RAM 中,所以直接通过索引读取数据,往往比扫描数据文档的方式更快,查询性能也更高。
使用覆盖索引查询
为了演示 MongoDB 覆盖索引查询,下面使用一个 users 集合作为示例:
{
"_id": ObjectId("53402597d852426020000002"),
"contact": "987654321",
"dob": "01-01-1991",
"gender": "M",
"name": "Tom Benzamin",
"user_name": "tombenzamin"
}
我们在 users 集合上创建一个联合索引,索引字段为 gender 和 user_name:
>db.users.createIndex({gender:1,user_name:1})
注:如果使用的是 5.0 之前的 MongoDB 版本,也可以使用 db.collection.ensureIndex();不过从 5.0 开始,ensureIndex() 已被移除,因此应改为使用 createIndex()。
现在,这个联合索引可以覆盖下面这条查询语句:
>db.users.find({gender:"M"},{user_name:1,_id:0})
也就是说,对于上面的查询,MongoDB 不需要再到数据库数据文件中读取完整文档。相反,它会直接从索引中提取所需数据,因此这是一种非常高效的查询方式。
由于当前索引并不包含 _id 字段,而 MongoDB 在查询结果中默认会返回 _id,所以我们需要在结果集中显式将 _id 排除,才能满足覆盖索引查询的条件。
下面这个示例没有排除 _id,因此查询就无法被索引完全覆盖:
>db.users.find({gender:"M"},{user_name:1})
最后,以下这类查询通常不能使用覆盖索引查询:
- 索引字段中包含数组字段
- 索引字段中包含子文档字段
