本文目录导读:

我来详细解释MongoDB中的单字段索引和复合索引。
单字段索引
基本概念
单字段索引是最简单的索引类型,只在一个字段上建立索引。
创建语法
// 升序索引
db.collection.createIndex({ fieldName: 1 })
// 降序索引
db.collection.createIndex({ fieldName: -1 })
// 唯一索引
db.collection.createIndex({ fieldName: 1 }, { unique: true })
示例
// 创建单字段索引
db.users.createIndex({ email: 1 })
// 创建唯一索引
db.users.createIndex({ username: 1 }, { unique: true })
// 创建降序索引(适用于日期排序)
db.orders.createIndex({ createdAt: -1 })
适用场景
- 精确匹配查询
- 范围查询
- 排序操作
复合索引
基本概念
复合索引在多个字段上建立索引,字段的顺序很重要。
创建语法
// 创建复合索引
db.collection.createIndex({ field1: 1, field2: -1 })
示例
// 查询用户按年龄和名字排序
db.users.createIndex({ age: 1, name: 1 })
// 订单按用户和日期查询
db.orders.createIndex({ userId: 1, createdAt: -1 })
复合索引的关键规则
最左前缀原则
复合索引支持所有前缀的查询:
// 创建索引: { a: 1, b: 1, c: 1 }
// 支持的查询
{ a: 1 } // 使用索引
{ a: 1, b: 2 } // 使用索引
{ a: 1, b: 2, c: 3 } // 使用索引
// 不支持的查询
{ b: 1 } // 不使用索引
{ c: 1 } // 不使用索引
{ b: 1, c: 1 } // 不使用索引
排序规则
复合索引的字段顺序影响排序操作:
// 索引: { age: 1, name: -1 }
// 支持的排序
db.users.find().sort({ age: 1, name: -1 }) // 使用索引
db.users.find().sort({ age: 1 }) // 使用索引
db.users.find().sort({ age: -1, name: 1 }) // 使用索引(反向)
// 不支持的排序
db.users.find().sort({ name: -1 }) // 不使用索引
db.users.find().sort({ age: -1, name: -1 }) // 不使用索引
实际应用示例
电商系统订单查询
// 需求:按用户查询订单,并按时间倒序排列
db.orders.createIndex({ userId: 1, createdAt: -1 })
// 高效查询
db.orders.find({ userId: "user123" }).sort({ createdAt: -1 })
db.orders.find({
userId: "user123",
createdAt: { $gte: ISODate("2024-01-01") }
}).sort({ createdAt: -1 })
社交媒体帖子搜索
// 需求:查询某个用户的帖子,按时间排序
db.posts.createIndex({ author: 1, timestamp: -1 })
// 覆盖查询
db.posts.find({
author: "user456",
timestamp: { $gt: ISODate("2024-06-01") }
}).sort({ timestamp: -1 })
最佳实践
索引设计原则
// ❌ 不好的设计
db.collection.createIndex({ field1: 1 })
db.collection.createIndex({ field1: 1, field2: 1 })
// ✅ 好的设计(复合索引包含单字段索引的功能)
db.collection.createIndex({ field1: 1, field2: 1 })
查询选择性
// 选择性高的字段放在前面
db.users.createIndex({
email: 1, // 高选择性(唯一)
status: 1 // 低选择性(只有几个值)
})
使用分析工具
// 查看查询是否使用索引
db.collection.find({ ... }).explain("executionStats")
// 查看集合索引
db.collection.getIndexes()
性能考虑
索引对写入的影响
- 每个索引都会增加写入操作的负担
- 复合索引通常比多个单字段索引更高效
内存使用
// 查看索引大小 db.collection.totalIndexSize() // 限制索引数量(建议不超过5个)
索引覆盖查询
// 查询的字段都在索引中
db.collection.createIndex({ name: 1, age: 1 })
db.collection.find(
{ name: "张三" },
{ _id: 0, name: 1, age: 1 }
)
// 这样查询只从索引中获取数据,不访问文档
常见问题
索引选择错误
// 使用hint()强制使用特定索引
db.collection.find({ ... }).hint({ field1: 1, field2: -1 })
索引失效的场景
- 使用$ne, $nin, $not操作符
- 在索引字段上使用函数
- 正则表达式(非前缀匹配)
合理使用单字段和复合索引,可以大幅提升MongoDB的查询性能,建议根据实际查询模式进行索引设计,避免过度索引。