你有没有遇到过这样的情况:明明只查一条用户信息,MongoDB 却要花好几秒?翻日志一看,executionTimeMillis 动不动就 2000+。其实问题很可能不在数据量大,而在——没建索引。
索引不是“可有可无”,是“查得快不快”的开关
想象一下图书馆:没有目录时,找一本《深入浅出Node.js》,你得挨个书架翻;有了按书名排序的索引,三秒定位。MongoDB 的索引也一样——它帮你把某字段的值提前排好序、建好查找路径,跳过全表扫描(collection scan)。
最常用:单字段索引
比如用户集合 users 经常按邮箱登录:
db.users.createIndex({ email: 1 })这里的 1 表示升序,-1 是降序,对单字段索引来说效果基本一致。建完再查:db.users.find({ email: "alice@example.com" }),响应立马从秒级降到毫秒级。
复合索引:多条件查询的加速器
如果经常查“北京地区、状态为启用、注册时间在半年内”的用户,别傻傻建三个单字段索引——用复合索引更高效:
db.users.createIndex({ city: 1, status: 1, createdAt: -1 })注意顺序:把等值匹配字段(city、status)放前面,范围查询字段(createdAt)放最后。这样 MongoDB 才能真正用上整个索引。
唯一索引:防重利器
邮箱不能重复?手机号必须唯一?加个 unique: true 就行:
db.users.createIndex({ phone: 1 }, { unique: true })下次插入重复手机号,MongoDB 直接报错 E11000 duplicate key,比应用层校验更可靠、更省事。
后台创建,不影响线上服务
数据量大的集合建索引会锁表?加个 background: true 就能边查边建:
db.orders.createIndex({ userId: 1, createdAt: -1 }, { background: true })虽然耗时稍长,但读写照常进行,适合白天在线业务。
怎么知道索引建对了?看执行计划
别猜,用 explain() 验证:
db.users.find({ email: "bob@test.com" }).explain("executionStats")重点看 nReturned(返回几条)、totalDocsExamined(扫了几条)。理想情况是两者相等,且 executionTimeMillis < 10;如果 totalDocsExamined 远大于 nReturned,说明索引没生效或没建对。