索引基础

索引是 MongoDB 用来加速查询的数据结构。

没有索引时,MongoDB 可能需要扫描整个集合。

有合适索引时,MongoDB 可以更快定位数据。

一、为什么需要索引

假设用户集合有 100 万条数据:

db.users.find({
  email: "zhangsan@example.com"
})

如果 email 没有索引,MongoDB 可能要从头扫到尾。

email 建索引:

db.users.createIndex({
  email: 1
})

以后按 email 查询会更快。

二、查看索引

db.users.getIndexes()

每个集合默认都有 _id 索引。

{
  key: { _id: 1 },
  name: "_id_"
}

三、单字段索引

db.users.createIndex({
  email: 1
})

1 表示升序,-1 表示降序。

对于普通等值查询,升序和降序差别不大。

四、唯一索引

邮箱不能重复时,可以建唯一索引:

db.users.createIndex(
  { email: 1 },
  { unique: true }
)

如果插入重复邮箱,会报错。

唯一索引适合:

  • 用户名
  • 邮箱
  • 手机号
  • 第三方登录 openid

五、复合索引

多个字段一起查询和排序时,可以使用复合索引。

db.posts.createIndex({
  status: 1,
  createdAt: -1
})

适合这种查询:

db.posts.find({
  status: "published"
}).sort({
  createdAt: -1
})

复合索引字段顺序很重要。

通常把高频过滤字段放前面,把排序字段放后面。

六、用 explain 看是否使用索引

db.posts.find({
  status: "published"
}).sort({
  createdAt: -1
}).explain("executionStats")

重点看:

字段含义
totalDocsExamined扫描了多少文档
totalKeysExamined扫描了多少索引键
executionTimeMillis执行耗时

如果扫描文档数量远大于返回数量,通常要考虑索引是否合适。

七、删除索引

先查看索引名:

db.users.getIndexes()

删除:

db.users.dropIndex("email_1")

不要随便在生产环境删除索引,可能导致接口突然变慢。

八、索引不是越多越好

索引的代价:

  • 占用磁盘空间。
  • 插入、更新、删除时要维护索引。
  • 索引太多会增加写入成本。

建议:

  • 高频查询字段建索引。
  • 排序字段结合查询条件建复合索引。
  • 低频后台查询不一定要建索引。
  • 定期检查没用的索引。