1. MongoDB 索引介绍
MongoDB 是一种灵活而且可扩展的 NoSQL 数据库,具有高度开放的体系结构和放松的一致性模型。MongoDB 的索引是执行高效查询的关键,可以避免遍历整个集合来获取数据。
索引的作用:
提高查询效率
可以创建唯一索引、建立对应关系
可以加速分组和排序操作
2. MongoDB 索引类型
MongoDB 支持主要三种类型的索引:
单键索引
复合索引
多键索引
2.1 单键索引
单键索引是对集合中单个字段的索引。可以通过显式指定该字段或 _id 自动生成的默认索引来创建。
创建单键索引的方法:
db.collection_name.createIndex({ fieldname: 1 })
查询单键索引的方法:
db.collection_name.find({ fieldname: value }).explain('executionStats')
执行上面的查询语句,在输出的执行计划中可以看到使用了单键索引。
2.2 复合索引
复合索引是对集合中多个字段的索引。比如,当你需要经常按照年龄进行排序和分组,同时又需要按照其他字段进行查询时,可以同时为年龄和其他字段创建一个复合索引。
创建复合索引的语法:
db.collection_name.createIndex( { age: -1, fieldname: 1 } )
这里我们创建了一个以 age 为递减顺序的复合索引,同时以 fieldName 字段为递增顺序的索引。
2.3 多键索引
多键索引是针对集合中的数组进行索引。对数组字段创建索引时,MongoDB 将在一个集合中创建一个索引项,每个数组值包含一个新的索引项。
创建多键索引的方法:
db.collection_name.createIndex({ fieldname: "text"})
查询多键索引的方法:
db.collection_name.find( { $text: { $search: "value" } } )
执行上面的查询语句,可以看到返回了包含 value 的所有文档。
3. 索引的使用方法
3.1 explain 方法
如果要知道 MongoDB 是否正在使用索引以及使用哪种索引,请使用 explain 方法。这个方法提供执行计划。
语法:
db.collection_name.find({ fieldname: value }).explain("executionStats")
返回结果:
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "dbname.collectionname",
"indexFilterSet" : false,
"parsedQuery" : {
"fieldname" : {
"$eq" : value
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"fieldname" : 1
},
"indexName" : "fieldname_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"fieldname" : [ ]
},
"indexBounds" : {
"fieldname" : [
"[\"value\", \"value\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"nReturned" : 0,
"executionTimeMillis" : 0,
"totalKeysExamined" : 0,
"totalDocsExamined" : 0,
"executionSuccess" : true,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 0,
"executionTimeMillisEstimate" : 0,
"works" : 1,
"advanced" : 0,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 0,
"executionTimeMillisEstimate" : 0,
"works" : 1,
"advanced" : 0,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"keyPattern" : {
"fieldname" : 1
},
"indexName" : "fieldname_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"fieldname" : [ ]
},
"indexBounds" : {
"fieldname" : [
"[\"value\", \"value\"]"
]
},
"keysExamined" : 0,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0
}
}
}
}
在该执行计划中,可以看到索引的使用情况(winngPlan)。在这个例子中,fieldname_1 是一个单键索引。
3.2 hint 方法
hint() 方法可以在查询中指定使用特定的索引。MongoDB 中的 hint() 方法需要使用 $命令,语法如下:
db.collection_name.find({}).hint({ indexname: 1 })
使用 hint() 方法的目的是强制 MongoDB 使用特定的索引,而不是执行计划所选择的默认索引。
3.3 covered query
covered query:是指 MongoDB 是从索引本身获取查询结果,而不是从文档中读取结果。
意义:
提高性能
减少磁盘 I/O
情况:
如果在查询中使用 covered query。返回结果的 projection (projection 是用于检索文档中某些字段的语句)不能包括任何字段(为空 projection {}),MongoDB 可以使用索引返回结果,并避免检查集合本身。
如果查询需要的数据不能全部使用索引获取,则需要检查其他列以完成查询。当出现这种情况时,指数只能回报索引行并不包含完整的映射行,并且将进行查询集合以获取所需的所有数据。
4. MongoDB 索引最佳实践
为了实现最佳的查询性能,下面的最佳实践对于数据访问和查询执行非常重要:
仅保存关键数据:在保留文档数据的同时,使用 $projection 过滤查询结果中不需要的数据。
针对经常执行的操作创建索引:注意对查询经常出现的字段进行索引。
选择最佳的索引类型:对不同类型的查询使用适当的索引。
删除不必要的索引:避免创建不必要的索引,因为它们可能浪费空间和 CPU 资源。
升级到最新版本的 MongoDB:每个新版本都有对索引的性能提升和更好的功能。
5. 总结
本文详细介绍了 MongoDB 索引的类型、使用方法和最佳实践。在实际应用中,需要根据业务特点和使用场景选择不同类型的索引,并对索引进行适当的维护和优化。