MongoDB 索引

MongoDB 索引概述

MongoDB 的索引是提升查询性能的核心机制。它在集合(collection)上为一个或多个字段创建有序的数据结构(默认是 B-tree),让数据库可以快速定位文档,而不必全表扫描。


1. 索引类型

类型说明典型场景
单字段索引 ({field: 1})最常见的索引按单一字段查询、排序
复合索引 ({a:1, b:-1})覆盖多个字段,顺序重要多字段过滤 + 排序
多键索引 (Multi-key)自动为数组字段创建查询数组中包含某值的文档
文本索引 ({content: "text"})全文搜索,支持语言停用词搜索文章、评论
地理空间索引 (2dsphere, 2d)经纬度查询附近地点、GeoJSON
哈希索引 ({field: "hashed"})哈希分片键分片集合的均匀分布
TTL 索引 ({createdAt: 1}, expireAfterSeconds)自动删除过期文档会话、日志
部分索引 (partialFilterExpression)只为满足条件的文档建索引状态为 “active” 的文档
稀疏索引 (sparse: true)只为存在该字段的文档建索引字段可选的情况
唯一索引 (unique: true)保证字段值唯一用户名、email

2. 创建索引的基本语法

// 单字段升序索引
db.collection.createIndex({ age: 1 })

// 复合索引(先按 status 升序,再按 createdAt 降序)
db.collection.createIndex({ status: 1, createdAt: -1 })

// 文本索引
db.articles.createIndex({ title: "text", body: "text" })

// TTL 索引(30 天后自动删除)
db.sessions.createIndex(
  { lastAccess: 1 },
  { expireAfterSeconds: 2592000 }
)

// 部分索引 + 唯一
db.users.createIndex(
  { email: 1 },
  { unique: true, partialFilterExpression: { status: "active" } }
)

提示createIndex幂等 的,重复执行只会返回已存在的索引信息。


3. 常用管理命令

命令作用
db.collection.getIndexes()查看集合所有索引
db.collection.dropIndex("indexName")删除指定索引
db.collection.dropIndexes()删除除 _id 外的所有索引
db.collection.totalIndexSize()索引占用的磁盘空间
explain("executionStats")查看查询是否命中索引、扫描文档数
// 示例:查看执行计划
db.users.find({ age: { $gte: 30 } }).explain("executionStats")

4. 索引使用原则(最佳实践)

  1. 为频繁查询的字段建索引
  • find()sort()aggregate() 中出现的字段。
  1. 遵循 ESR 原则(Equality-Sort-Range)
  • 复合索引顺序:等值条件 → 排序字段 → 范围条件
   // 推荐
   { status: 1, createdAt: -1, score: 1 }
   // 查询:status="active" + 按 createdAt 降序 + score > 80
  1. 覆盖索引(Covered Query)
  • 查询只返回索引中的字段,无需访问文档,极大提升性能。
   db.users.createIndex({ email: 1, name: 1 })
   db.users.find({ email: "a@x.com" }, { _id: 0, name: 1 }) // 完全覆盖
  1. 避免过度索引
  • 每个写操作(insert/update/delete)都会更新索引,写放大。
  • 定期使用 db.collection.stats() 检查 indexSizesize 比例。
  1. 使用 hint() 强制指定索引(调试时)
   db.orders.find({ customerId: 123 }).hint({ customerId: 1, orderDate: -1 })

5. 常见问题排查

症状检查点
查询慢explain()totalDocsExamined 是否接近集合文档数
写性能下降indexSize 过大、索引太多
唯一约束冲突检查 unique 索引、是否有 null 或重复值
内存 OOM索引不适合 working set,导致频繁页面错误

6. 示例:完整实战案例

// 1. 创建集合
db.createCollection("orders")

// 2. 插入示例数据
db.orders.insertMany([
  { customerId: 1, status: "pending",   orderDate: ISODate("2025-10-01"), total: 99 },
  { customerId: 2, status: "completed", orderDate: ISODate("2025-10-05"), total: 150 },
  { customerId: 1, status: "completed", orderDate: ISODate("2025-11-01"), total: 200 }
])

// 3. 创建复合索引(ESR 原则)
db.orders.createIndex(
  { customerId: 1, status: 1, orderDate: -1 }
)

// 4. 查询 + 排序(命中索引)
db.orders.find({
  customerId: 1,
  status: "completed"
}).sort({ orderDate: -1 })

// 5. 验证覆盖查询
db.orders.createIndex({ customerId: 1, total: 1 }, { name: "cust_total" })
db.orders.find(
  { customerId: 1 },
  { _id: 0, total: 1 }
).hint("cust_total")   // 完全在索引中完成

7. 进一步学习资源


如需针对 特定查询分片环境Atlas 的索引优化示例,欢迎提供更多细节,我可以给出更精准的方案!

文章已创建 2371

发表回复

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

相关文章

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

返回顶部