1.单键值索引
单键索引。
name字段上创建一个索引。
sql>db.testindx.ensureIndex({"Name":1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
--创建索引并查看执行计划。
db.testindx.ensureIndex({"Name":1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
> db.testindx.find({"Name":"user9"}).explain("allPlansExecution")
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "myprocdb.testindx",
"indexFilterSet" : false,
"parsedQuery" : {
"Name" : {
"$eq" : "user9"
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"Name" : 1
},
"indexName" : "Name_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"Name" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"Name" : [
"[\"user9\", \"user9\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 1,
"totalKeysExamined" : 1,
"totalDocsExamined" : 1,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"Name" : 1
},
"indexName" : "Name_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"Name" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"Name" : [
"[\"user9\", \"user9\"]"
]
},
"keysExamined" : 1,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
},
"allPlansExecution" : [ ]
},
"serverInfo" : {
"host" : "itpuxdb1",
"port" : 27017,
"version" : "4.0.2",
"gitVersion" : "fc1573ba18aee42f97a3bb13b67af7d837826b47"
},
"ok" : 1
}
--"indexName" : "Name_1"
--"totalDocsExamined" : 1
可以看到使用了索引。
2.复合索引
2.复合索引。
创建一个索引时,应该牢记,索引要覆盖大多数查询。
sql>db.testindx.ensureIdex({"Name":1,"Age":1}) --创建名字和年龄复合索引。
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 2,
"numIndexesAfter" : 3,
"ok" : 1
}
创建复合索引时,第一个字段需要精确匹配,其后的是要用在范围中的字段。
sql>db.testindx.find({"Name":"user5","Age":{"$gt":25}}).explain("allPlansExecution")
> db.testindx.find({"Name":"user5","Age":{"$gt":25}}).explain("allPlansExecution")
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "myprocdb.testindx",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"Name" : {
"$eq" : "user5"
}
},
{
"Age" : {
"$gt" : 25
}
}
]
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"Name" : 1,
"Age" : 1
},
"indexName" : "Name_1_Age_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"Name" : [ ],
"Age" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"Name" : [
"[\"user5\", \"user5\"]"
],
"Age" : [
"(25.0, inf.0]"
]
}
}
},
"rejectedPlans" : [
{
"stage" : "FETCH",
"filter" : {
"Age" : {
"$gt" : 25
}
},
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"Name" : 1
},
"indexName" : "Name_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"Name" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"Name" : [
"[\"user5\", \"user5\"]"
]
}
}
}
]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 0,
"totalKeysExamined" : 1,
"totalDocsExamined" : 1,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 3,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"Name" : 1,
"Age" : 1
},
"indexName" : "Name_1_Age_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"Name" : [ ],
"Age" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"Name" : [
"[\"user5\", \"user5\"]"
],
"Age" : [
"(25.0, inf.0]"
]
},
"keysExamined" : 1,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
},
"allPlansExecution" : [
{
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"totalKeysExamined" : 1,
"totalDocsExamined" : 1,
"executionStages" : {
"stage" : "FETCH",
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"Name" : 1,
"Age" : 1
},
"indexName" : "Name_1_Age_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"Name" : [ ],
"Age" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"Name" : [
"[\"user5\", \"user5\"]"
],
"Age" : [
"(25.0, inf.0]"
]
},
"keysExamined" : 1,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
{
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"totalKeysExamined" : 1,
"totalDocsExamined" : 1,
"executionStages" : {
"stage" : "FETCH",
"filter" : {
"Age" : {
"$gt" : 25
}
},
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"docsExamined" : 1,
"alreadyHasObj" : 0,
"inputStage" : {
"stage" : "IXSCAN",
"nReturned" : 1,
"executionTimeMillisEstimate" : 0,
"works" : 2,
"advanced" : 1,
"needTime" : 0,
"needYield" : 0,
"saveState" : 0,
"restoreState" : 0,
"isEOF" : 1,
"invalidates" : 0,
"keyPattern" : {
"Name" : 1
},
"indexName" : "Name_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"Name" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"Name" : [
"[\"user5\", \"user5\"]"
]
},
"keysExamined" : 1,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
}
]
},
"serverInfo" : {
"host" : "itpuxdb1",
"port" : 27017,
"version" : "4.0.2",
"gitVersion" : "fc1573ba18aee42f97a3bb13b67af7d837826b47"
},
"ok" : 1
}
3.mongodb的排序操作
3.对sort()操作的支持。
在mongodb中使用一个索引字段来对文档排序的sort操作会提供最佳的性能。
如果一个索引被用于访问文档,那么他将按照与索引相同的顺序返回结果。
复合索引输出结果可以按照索引前缀的顺序或者完整索引的顺序来排序。
前缀索引时复合索引的一个子集,它包含开头部分的一个或多个字段。
sql>db.testindx.ensureIndex({"Age":1,"Name":1,"Class":1})
sql>db.testindx.find().sort({"Age":1}) --按年龄排序。
sql>db.testindx.find().sort({"Age":1,"Name":1})
sql>db.testindx.find().sort({"Age":1,"Name":1,"Class":1})
上面的索引在以下查询中没有用处,就第一个排序字段必须是符合索引的第一个前缀。
sql>db.testindx.find().sort({"Gender":1,"Age":1,"Name":1})
4.唯一索引
唯一索引。
如果唯一性是需要被启用的其中一个约束,那么在创建该索引时,这个唯一属性就需要被设置为true;
sql>db.testindx.dropIndexes() --删除已有的索引。
sql>db.testindx.ensureIndex({"Name":1},{"unique":true}) --创建唯一索引。
sql>db.testindx.insert({"Name":"uniquename"})
WriteResult({ "nInserted" : 1 })
sql> db.testindx.insert({"Name":"uniquename"}) --重复插入就会报错。
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 11000,
"errmsg" : "E11000 duplicate key error collection: myprocdb.testindx index: Name_1 dup key: { : \"uniquename\" }"
}
})
sql>db.testindx.find({"Name":"uniquename"})
{ "_id" : ObjectId("4cabde1e6933f3a279550a90"), "Name" : "uniquename" } --只有一个文档。
也可以为复合索引启用唯一性。
sql>db.testindx.ensureIndex({"Name":1,"Age":1},{"unique":true})
sql>db.testindx.insert({"Name":"usercit"})
WriteResult({ "nInserted" : 1 })
> db.testindx.insert({"Name":"usercit","Age":30})
WriteResult({ "nInserted" : 1 })
可以在先创建集合并且插入数据,然后在该集合上创建一个索引。如果在该集合上创建一个
唯一索引,而创建索引的字段可能存在重复值的话,那么索引的创建将会失败。
为满足这一场景,mongodb提供dropDups选享。它会保留找到的文档,并删除后面重复的文档。
sql>db.testindx.ensureIndex({"Name":1},{"unique":true,"dropDups":true})
db.testindx.ensureIndex({"Name":1},{"unique":true,"dropDups":true})
{
"ok" : 0,
"errmsg" : "E11000 duplicate key error collection: myprocdb.testindx index: Name_1 dup key: { : \"usercit\" }",
"code" : 11000,
"codeName" : "DuplicateKey"
}
>
>
> db.version()
4.0.2
--我的当前环境是mongodb4.0.2;dropDups属性居然一直报错。
5.索引的其他维护操作
5.system.indexes
无论何时创建一个数据库,默认情况下都会创建一个system.indexes集合。关于数据库索引的信息
都存储在system.indexes集合中。这是一个保留集合,无法修改或删除。只能通过ensureIndex
和dropIndexes数据库命令来操作它。
sql>db.myprocdb.getIndexes() --查看集合上所有的索引。
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "myprocdb.testindx"
}
]
6.dropIndex --删除索引。
sql>db.testindx.dropIndex({"Name":1}) --删除Name列的索引。
{ "nIndexesWas" : 2, "ok" : 1 }
7.reIndex --重构索引。
它会重构一个集合上的所有索引,它会首先删除索引,其中包括_id字段上的默认索引。然后重构
这些索引。
sql>db.testindx.reIndex();
{
"nIndexesWas" : 1,
"nIndexes" : 1,
"indexes" : [
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "myprocdb.testindx"
}
],
"ok" : 1
}
6.索引如何工作总结
8.索引如何工作。
mongodb会在一个二叉树结构中存储索引,因此它自动支持范围查询。
如果一个查询中使用了多个选择条件,那么mongodb会尝试找到最佳的单个索引来选择一个候选集。
在那之后,它会遍历集合来估算其他条件。
在首次执行查询时,mongodb会为每一个可用于该查询的索引创建多个执行计划。他会让这些执行计划
在一定时间间隔中轮流执行,直到执行最快的计划完成。然后其结果会被返回到系统。该结果
会记住最快执行计划使用的索引。
对于后续查询,将会使用此被记住的索引,直到该集合发生了一定数量的更新。
在超过更新限制时,系统将再次执行该处理过程以找出此时适用的最佳索引。
发生以下事件重新评估索引:
集合接收到1000个写操作。
添加或删除了一个索引。
mongod程序重启了
发生了用于重构索引的再次索引。
版本2.6之前,mongodb都仅使用一个索引。为更好匹配查询,可以创建组合索引。
版本2.6之后,引入索引交集。他使得用于满足具有复合条件的查询的索引交集成为可能。
其中一部分条件由一个索引满足,其他部分则由其他索引满足。
一般,索引交集是由两个索引组成。可以将多个索引用于解决一个查询。
为了维持一个最佳平衡,需要定期检查使用一个索引的有效性。这可以通过你在系统上执行、
的读和写的比例来平衡。识别出较少使用的索引并且删除它们。