MongoDB - 覆盖查询
MongoDB - 覆盖查询
Section titled “MongoDB - 覆盖查询”本章探讨 MongoDB 中最强大的性能优化技术之一:覆盖查询。
什么是覆盖查询?
Section titled “什么是覆盖查询?”覆盖查询是指完全可以使用索引来满足的查询,而无需检查任何文档。这在以下情况下可能实现:
- 查询筛选器中使用的所有字段都是索引的一部分。
- 查询投影中返回的所有字段也都在同一个索引中。
由于索引以高效的数据结构存储在 RAM 中,MongoDB 可以极快地回答覆盖查询。它避免了从磁盘获取文档这个慢得多的过程,而这通常是主要的性能瓶颈。
覆盖查询示例
Section titled “覆盖查询示例”考虑一个 users 集合,其中包含类似这样的文档:
{ "_id": ObjectId("64f8a55b23e8b1e1ab654321"), "username": "johndoe", "status": "active", "reputation": 250}首先,让我们在 status 和 username 字段上创建一个复合索引以支持我们的查询。
// Using mongoshdb.users.createIndex({ status: 1, username: 1 })现在,我们可以执行一个由该索引“覆盖”的查询。请注意,投影明确请求 username 和 status,并排除了 _id。
db.users.find( { status: "active" }, // Query filter uses an indexed field { username: 1, status: 1, _id: 0 } // Projection uses only indexed fields)验证覆盖查询
Section titled “验证覆盖查询”要确认查询是否是覆盖的,我们使用 .explain('executionStats') 方法。
db.users.find( { status: "active" }, { username: 1, status: 1, _id: 0 }).explain('executionStats')输出将是一个大型 JSON 对象。请查找这些关键指标:
- 在
queryPlanner.winningPlan.stage中,您将看到PROJECTION_COVERED而不是PROJECTION_DEFAULT。 - 其前面的阶段将是
IXSCAN(索引扫描),而不是COLLSCAN(集合扫描)。 - 在
executionStats中,totalDocsExamined将为0。这是明确的证明:MongoDB 无需查看任何完整的文档即可返回结果。
忘记排除 _id
Section titled “忘记排除 _id”默认情况下,MongoDB 总是返回 _id 字段。如果您的索引不包含 _id,但您在投影中忘记明确排除它(_id: 0),则查询将不会被覆盖。MongoDB 将不得不为了获取 _id 而获取整个文档,从而适得其反。
// THIS QUERY IS NOT COVERED because _id is not in the indexdb.users.find({ status: "active" }, { username: 1, status: 1 })在数组上建立索引
Section titled “在数组上建立索引”虽然在数组字段上的多键索引可以用于覆盖查询,但它有某些限制。如果查询投影了一个用多键索引建立索引的数组字段,则无法使用覆盖查询。