MongoDB 高级索引

MongoDB 高级索引(Advanced Indexing)完全指南

核心目标用对索引,性能翻 100 倍 —— 覆盖 复合、部分、稀疏、TTL、文本、地理、多键、哈希、分片键 等全场景。


一、索引类型总览

类型用途关键选项
单一索引单字段createIndex({ field: 1 })
复合索引多字段createIndex({ a: 1, b: -1 })
部分索引(Partial)条件索引partialFilterExpression
稀疏索引(Sparse)跳过缺失字段sparse: true
TTL 索引自动过期expireAfterSeconds
文本索引(Text)全文搜索weights, default_language
地理索引(2d/2dsphere)位置查询2dsphere
哈希索引(Hashed)分片键均匀分布hashed
多键索引(Multikey)数组字段自动创建
通配符索引(Wildcard)动态字段$**

二、复合索引:黄金法则 ESR

Equality → Sort → Range

// 查询:status="active" + 按 score 降序 + age > 18
db.users.createIndex({
  status: 1,     // 等值
  score: -1,     // 排序
  age: 1         // 范围
})

能支持的查询

  • { status: "active" }
  • { status: "active", score: { $gte: 90 } }
  • { status: "active", age: { $gt: 18 } }
  • { status: "active", score: -1, age: { $gt: 18 } }

三、部分索引(Partial Index)—— 节省 90% 空间

// 只为 status="active" 的文档建索引
db.users.createIndex(
  { email: 1 },
  { 
    partialFilterExpression: { status: "active" } 
  }
)

适用:高频查询字段 + 过滤条件固定


四、稀疏索引(Sparse)—— 避免 null 膨胀

// 只为存在 phone 的文档建索引
db.users.createIndex(
  { phone: 1 },
  { sparse: true }
)

vs 部分索引

  • sparse: 字段存在即可
  • partial: 可加复杂条件

五、TTL 索引:自动清理日志

db.sessions.createIndex(
  { createdAt: 1 },
  { expireAfterSeconds: 3600 }  // 1 小时后删除
)

注意:字段必须是 Date,每 60 秒检查一次


六、文本索引:全文搜索

// 创建文本索引
db.articles.createIndex({
  title: "text",
  content: "text",
  tags: "text"
}, {
  weights: { title: 10, content: 5, tags: 1 },
  default_language: "chinese"
})

// 搜索
db.articles.find({
  $text: { $search: "MongoDB 性能" }
})

排序$meta: "textScore"

db.articles.find(
  { $text: { $search: "索引" } },
  { score: { $meta: "textScore" } }
).sort({ score: { $meta: "textScore" } })

七、地理索引:附近的人

// 2dsphere(地球)
db.places.createIndex({ location: "2dsphere" })

// 插入 GeoJSON
db.places.insertOne({
  name: "咖啡馆",
  location: {
    type: "Point",
    coordinates: [116.39, 39.9]  // [经度, 纬度]
  }
})

// 附近 5km
db.places.find({
  location: {
    $near: {
      $geometry: {
        type: "Point",
        coordinates: [116.40, 39.91]
      },
      $maxDistance: 5000  // 米
    }
  }
})

八、哈希索引:分片键均匀分布

// 分片键使用 hashed
sh.shardCollection("mydb.logs", { _id: "hashed" })

避免热点写入(如自增 _id


九、多键索引(Multikey):数组字段

// 自动为数组建多键索引
db.users.createIndex({ tags: 1 })

// 查询
db.users.find({ tags: "mongodb" })

限制

  • 不能与 hashed 共用
  • 分片键不能是数组

十、通配符索引(Wildcard):动态字段

// 索引 user.profile 下的所有字段
db.users.createIndex({
  "profile.$**": 1
})

// 支持
db.users.find({ "profile.city": "Beijing" })

十一、索引管理命令

命令用途
getIndexes()查看索引
dropIndex("name")删除索引
createIndex(..., { background: true })后台建索引
collMod修改索引选项
reIndex()重建索引
// 查看索引大小
db.users.stats().indexSize

// 后台建索引(不阻塞)
db.users.createIndex({ email: 1 }, { background: true })

十二、生产级索引策略

场景推荐索引
用户登录{ email: 1 } + unique
文章列表{ status: 1, createdAt: -1, _id: 1 }
日志查询{ level: 1, timestamp: -1 } + partial: { level: "error" }
分片键{ _id: "hashed" }{ user_id: 1, date: 1 }
全文搜索{ title: "text", content: "text" }

十三、索引优化 Checklist

检查项命令
是否重复索引?getIndexes()
索引是否被使用?explain().winningPlan.indexName
索引大小?stats().indexSize
是否覆盖查询?PROJECTION_COVERED
是否后台建?{ background: true }

十四、终极案例:高并发日志系统

// 1. 复合索引(ESR)
db.logs.createIndex({
  app: 1,           // 等值
  level: 1,         // 等值
  timestamp: -1,    // 排序
  message: 1        // 投影(覆盖)
})

// 2. 部分索引(只存 error)
db.logs.createIndex(
  { request_id: 1 },
  { partialFilterExpression: { level: "error" } }
)

// 3. TTL 清理旧日志
db.logs.createIndex(
  { timestamp: 1 },
  { expireAfterSeconds: 30 * 24 * 3600 }  // 30 天
)

// 4. 查询(覆盖)
db.logs.find(
  { app: "api", level: "error" },
  { message: 1, timestamp: 1, _id: 0 }
)
.sort({ timestamp: -1 })
.limit(100)
.explain()
{
  "totalDocsExamined": 0,
  "stage": "PROJECTION_COVERED"
}

总结:高级索引黄金三问

问题答案
1. 索引顺序对吗?遵循 ESR
2. 索引是否必要?explain() 验证
3. 索引是否高效?覆盖查询 + 部分索引

你现在可以:

// 一行创建生产级索引
db.collection.createIndex(
  { status: 1, createdAt: -1, name: 1 },
  { partialFilterExpression: { status: "active" } }
)

把你的查询贴给我,我 30 秒出最优索引:

  1. 查询语句find / aggregate
  2. 过滤条件
  3. 返回字段 + 排序

回复 3 行代码,我生成:索引 + explain + 性能对比!

文章已创建 2371

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部