MongoDB索引通过构建高效查询路径,从根本上改变数据检索方式。当未建立索引时,数据库引擎被迫执行全集合扫描(COLLSCAN),如同在无序的书架上逐本查找目标书籍。通过建立索引,查询复杂度从O(n)降为O(log n),在百万级文档的集合中,查询速度可提升数百倍。
示例场景:用户表包含username
字段,未建索引时find({username: "alice"})
需要扫描全部文档。建立索引后,查询直接定位到目标文档。find({username: "alice"})
需要扫描全部文档。 建立索引后,查询
MongoDB采用B-Tree数据结构(非MySQL的B+Tree),每个节点存储键值对和子节点指针。B-Tree的特性保证:MongoDB采用B-Tree数据结构(非MySQL的B+Tree),每个节点存储键值对和子节点指针。 B-Tree的特性保证:
平衡树结构:所有叶子节点位于相同深度
高效范围查询:顺序存储的键值支持快速区间遍历
动态平衡:插入/删除时自动调整结构
// 创建年龄字段降序索引
db.users.createIndex({ age: -1 })
适用场景:单个条件查询或排序
排序方向影响:仅对覆盖查询的排序结果有效
db.orders.createIndex({ customer_id: 1, order_date: -1 })
最左前缀原则:查询必须包含左侧字段才能触发索引
排序优化:{a:1, b:-1}
索引可支持{a:1, b:-1}
索引可支持'a ASCa ASC, b DESC
的排序需求
索引类型 | 命令示例 | 应用场景 |
---|---|---|
多键索引 | 自动为数组字段创建 | 商品标签数组["book","tech"] |
地理空间索引 | 'db.places.createIndex({ locdb.places.createIndex({ loc: "2dsphere" }) |
附近地点搜索 |
文本索引 | 'db.articles.createIndex({ content:db.articles.createIndex({ content: "text" }) |
全文检索 |
哈希索引 | 'db.logs.createIndex({ _id:db.logs.createIndex({ _id: "hashed" }) |
分片键均匀分布 |
TTL索引(自动清理)
// 日志保留24小时
db.logs.createIndex({ create_time: 1 }, { expireAfterSeconds: 86400 })
部分索引(存储优化)
// 只索引VIP用户
db.users.createIndex(
{ vip: 1 },
{ partialFilterExpression: { vip: true } }
)
稀疏索引(空间优化)
// 忽略无phone字段的文档
db.contacts.createIndex({ phone: 1 }, { sparse: true })
// 查看索引详情
db.products.getIndexes()
// 创建带自定义名称的索引
db.orders.createIndex(
{ status: 1, amount: -1 },
{ name: "status_amount_idx" }
)
// 删除指定索引
db.sales.dropIndex("region_sales_idx")
// 分析查询执行计划
db.orders.find({
customer_id: "C123",
order_date: { $gt: ISODate("2023-01-01") }
}).explain("executionStats")
关键指标解读:
totalKeysExamined
:扫描索引键数量
totalDocsExamined
:检查文档数量
executionTimeMillis
:实际执行时间
// 创建复合索引
db.employees.createIndex({ dept: 1, salary: 1 })
// 覆盖查询示例
db.employees.find(
{ dept: "Engineering" },
{ _id: 0, dept: 1, salary: 1 }
)
实现条件:
查询所有字段必须包含在索引中
结果排除_id
字段(除非索引包含_id
)
ESR原则:相等匹配(Equality)字段在前,排序(Sort)字段居中,范围查询(Range)字段在后
写读比例:索引使写操作成本增加约5%,需平衡读写频率
内存优化:确保常用索引可完全载入内存
过度索引:每个额外索引增加写入开销
索引键顺序错误:{a:1, b:1}
与{b:1, a:1}
性能差异显著
低效运算符:$exists
、$ne
等可能导致索引失效
场景:电商订单查询缓慢
// 原始查询
db.orders.find({
user_id: "U1001",
status: "shipped",
order_date: { $gte: ISODate("2023-06-01") }
}).sort({ amount: -1 })
优化步骤:
分析现有索引:发现使用全表扫描
创建复合索引:
db.orders.createIndex({
user_id: 1,
status: 1,
order_date: 1,
amount: -1
})
验证执行计划:确认使用IXSCAN并覆盖排序
优化后结果:查询时间从1200ms降至15ms
合理使用索引可使MongoDB查询性能提升10-100倍,但需要持续监控和优化。建议:
使用$indexStats
分析索引使用情况
定期执行explain()
分析慢查询explain()
分析慢查询
结合Compass可视化工具进行索引管理
通过深入理解索引机制,结合业务场景设计最优索引策略,可充分发挥MongoDB的高性能优势,构建高效稳定的数据库系统。