MST

星途 面试题库

面试题:MongoDB索引优化之覆盖索引的应用

解释MongoDB中覆盖索引的概念,如何判断一个查询是否利用了覆盖索引?请举例说明在实际开发中,怎样设计查询和索引以利用覆盖索引来提升查询性能。如果查询中包含排序操作,覆盖索引还能生效吗,为什么?
22.7万 热度难度
数据库MongoDB

知识考点

AI 面试

面试题答案

一键面试

1. 覆盖索引的概念

覆盖索引指的是查询所需的所有数据都可以从索引本身获取,而无需再去读取文档。在MongoDB中,索引是一种特殊的数据结构,它以某种特定顺序存储文档中字段的值,便于快速查找。当索引包含了查询所需要的所有字段时,MongoDB可以直接从索引中提取数据返回给客户端,而不必再通过索引定位到文档然后读取文档内容,这样可以极大地减少I/O操作,提高查询性能。

2. 判断查询是否利用了覆盖索引

可以使用explain()方法来判断查询是否利用了覆盖索引。例如,假设有一个集合students,包含字段nameagegrade,并在nameage上建立了复合索引{name: 1, age: 1}

// 查询语句
db.students.find({name: "Alice", age: 20}, {name: 1, age: 1, _id: 0})
// 使用explain查看执行计划
db.students.find({name: "Alice", age: 20}, {name: 1, age: 1, _id: 0}).explain("executionStats")

explain的输出结果中,如果"stage": "IXSCAN"(表示使用了索引扫描)且"indexOnly": true,则说明该查询利用了覆盖索引。

3. 实际开发中利用覆盖索引提升查询性能

假设在一个电商系统中,有一个products集合,包含字段productNamepricedescription等。如果经常需要根据productName查询price,可以这样设计:

  • 创建索引
db.products.createIndex({productName: 1, price: 1})
  • 编写查询
db.products.find({productName: "iPhone 14"}, {productName: 1, price: 1, _id: 0})

这样的查询就可以利用覆盖索引,因为索引中包含了查询所需的productNameprice字段,无需再读取文档。

4. 排序操作与覆盖索引

如果查询中包含排序操作,覆盖索引仍然可以生效,但有一定条件。

  • 条件满足时生效:当排序字段包含在覆盖索引中,且索引顺序与排序顺序一致时,覆盖索引可以生效。例如,集合users有字段nameage,建立索引{name: 1, age: 1}。查询db.users.find({name: /^A/}, {name: 1, age: 1, _id: 0}).sort({name: 1, age: 1}),由于排序字段nameage都在索引中且顺序与索引一致,所以覆盖索引生效。
  • 条件不满足时失效:如果排序字段不在覆盖索引中,或者索引顺序与排序顺序不一致,覆盖索引可能失效。比如查询db.users.find({name: /^A/}, {name: 1, age: 1, _id: 0}).sort({age: -1}),虽然age在索引中,但索引顺序是{name: 1, age: 1},而排序是{age: -1},此时覆盖索引可能无法生效,MongoDB可能需要读取文档来进行排序操作。