索引优化
索引基础
索引是提高数据库查询性能的关键技术。在MongoDB中,索引是一种特殊的数据结构,它存储了集合中特定字段的值,并按一定顺序排列,使得查询操作能够快速定位到所需的文档。
索引类型
单字段索引
单字段索引是最基本的索引类型,它只包含一个字段。
javascript
// 创建单字段索引
db.users.createIndex({ name: 1 })
// 创建降序索引
db.users.createIndex({ age: -1 })
复合索引
复合索引包含多个字段,字段顺序很重要。
javascript
// 创建复合索引
db.users.createIndex({ city: 1, age: -1 })
多键索引
多键索引用于包含数组字段的文档。
javascript
// 假设用户文档有hobbies数组字段
db.users.createIndex({ hobbies: 1 })
文本索引
文本索引支持文本搜索操作。
javascript
// 创建文本索引
db.articles.createIndex({ title: "text", content: "text" })
// 使用文本索引进行搜索
db.articles.find({ $text: { $search: "MongoDB性能优化" } })
地理空间索引
地理空间索引支持地理空间查询。
javascript
// 创建2dsphere索引
db.places.createIndex({ location: "2dsphere" })
// 查询附近的地点
db.places.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [116.4074, 39.9042] // 北京坐标
},
$maxDistance: 1000 // 1000米范围内
}
}
})
哈希索引
哈希索引将字段值的哈希值作为索引,支持基于哈希的分片。
javascript
// 创建哈希索引
db.users.createIndex({ username: "hashed" })
索引管理
查看索引
javascript
// 查看集合的所有索引
db.users.getIndexes()
// 查看索引统计信息
db.users.stats({ indexDetails: true })
删除索引
javascript
// 删除指定索引
db.users.dropIndex({ name: 1 })
// 删除所有索引
db.users.dropIndexes()
索引重建
javascript
// 重建所有索引
db.users.reIndex()
索引优化策略
索引选择原则
- 选择性:选择性高的字段更适合创建索引,即字段值重复较少的字段
- 查询频率:经常用于查询条件的字段应该创建索引
- 排序需求:经常用于排序的字段应该创建索引
- 覆盖查询:如果索引包含了查询所需的所有字段,可以避免回表查询
复合索引顺序
复合索引中字段的顺序很重要,应该将选择性最高的字段放在前面:
javascript
// 假设city字段选择性较低,age字段选择性较高
// 应该这样创建索引
db.users.createIndex({ age: 1, city: 1 })
// 而不是
db.users.createIndex({ city: 1, age: 1 })
索引大小监控
索引会占用存储空间,需要监控索引大小:
javascript
// 查看集合统计信息,包括索引大小
db.users.stats()
// 查看数据库统计信息
db.stats()
索引性能分析
explain()方法
使用explain()
方法分析查询执行计划:
javascript
// 分析查询执行计划
db.users.find({ age: { $gt: 25 } }).explain("executionStats")
// 分析聚合查询执行计划
db.users.aggregate([
{ $match: { age: { $gt: 25 } } }
]).explain("executionStats")
查询计划解读
在explain()
的输出中,重点关注以下信息:
stage
:使用的查询阶段indexUsed
:使用的索引docsExamined
:检查的文档数量executionTimeMillis
:执行时间
索引与分片
在分片集群中,索引对分片键的选择和查询路由有重要影响:
分片键索引
分片键会自动创建索引:
javascript
// 启用分片并指定分片键
db.adminCommand({ enableSharding: "myDatabase" })
db.adminCommand({ shardCollection: "myDatabase.users", key: { city: 1 } })
分片查询优化
在分片环境中,查询应该尽可能包含分片键以提高性能:
javascript
// 高效的分片查询
db.users.find({ city: "北京" })
// 低效的分片查询(需要查询所有分片)
db.users.find({ age: { $gt: 25 } })
实践项目
在博客系统中实现索引优化:
- 为文章集合创建合适的索引以提高查询性能
- 为评论集合创建复合索引以支持按文章ID和时间排序的查询
- 使用
explain()
分析查询性能并优化索引 - 监控索引大小和查询性能变化