如果学过关系型数据库比如MySQL那你就应该明白索引的好处,尤其是对于数据量非常大的数据集特别明显
下面的所有的first 代表的是集合
准备数据
>for(i=0;i<10000;i++){db.first.insert({title:"标题"+i})} //可以直接用命令行for循环添加数据
我就不全显示了,太多了,就显示数量
> db.first.find().count()
10000
利用explain进行分析查询语句,为了显示时间长点,就搜索最后的文档
db.first.find({title:"标题9999"}).explain("executionStats")
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.first",
"indexFilterSet" : false,
"parsedQuery" : {
"title" : {
"$eq" : "标题9999"
}
},
"winningPlan" : {
"stage" : "COLLSCAN",
"filter" : {
"title" : {
"$eq" : "标题9999"
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 14, //主要是这个,显示时间用了多少,单位是ms
"totalKeysExamined" : 0,
"totalDocsExamined" : 10000,
"executionStages" : {
"stage" : "COLLSCAN",
"filter" : {
"title" : {
"$eq" : "标题9999"
}
},
"nReturned" : 1,
"executionTimeMillisEstimate" : 10,
"works" : 10002,
"advanced" : 1,
"needTime" : 10000,
"needYield" : 0,
"saveState" : 78,
"restoreState" : 78,
"isEOF" : 1,
"invalidates" : 0,
"direction" : "forward",
"docsExamined" : 10000
}
},
"serverInfo" : {
"host" : "LAPTOP-H3U7J3BH",
"port" : 27017,
"version" : "4.0.10",
"gitVersion" : "c389e7f69f637f7a1ac3cc9fae843b635f20b766"
},
"ok" : 1
}
“executionTimeMillis” : 14 显示用时14ms ,记住这个时间,下面用索引来比较时间效率
1、创建索引
语法
db.collection.ensureIndex({索引的字段:1})
1为指定按升序创建索引,如果你想按降序来创建索引指定为**-1**即可。
多个索引字段:
一个索引有时候不能满足所需,所以要创建多个,像关系型数据库中的复合索引
db.collection.ensureIndex({索引的字段1:1,索引的字段2:1,索引的字段3:1})
ensureIndex()还可接受其他的参数
Parameter | Type | Description |
---|---|---|
background | Boolean | 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 “background” 可选参数。 “background” 默认值为false |
unique | Boolean | 建立的索引是否唯一。指定为true创建唯一索引。默认值为false |
name | string | 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称 |
dropDups | Boolean | 在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false |
sparse | Boolean | 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false |
expireAfterSeconds | integer | 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间 |
v | index version | 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本 |
weights | document | 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重 |
default_language | string | 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语 |
language_override | string | 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language |
2、显示所有索引
语法db.collection.getIndexes()
> db.first.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "test.first"
},
{
"v" : 2,
"key" : {
"title" : 1
},
"name" : "title_1",
"ns" : "test.first"
},
{
"v" : 2,
"key" : {
"title" : -1
},
"name" : "title_-1",
"ns" : "test.first"
}
]
3、删除指定索引
语法db.collection.dropIndex(key)
key是上面的name,比如你创建某个字段的索引,就会生成name为:某字段_1/-1,删除字段根据name开删除
> db.first.dropIndex("title_1")
{ "nIndexesWas" : 3, "ok" : 1 }
测试效率
添加升序索引字段
> db.first.ensureIndex({title:1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
再次用explain来分析查询语句
db.first.find({title:"标题9999"}).explain("executionStats")
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.first",
"indexFilterSet" : false,
"parsedQuery" : {
"title" : {
"$eq" : "标题9999"
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"title" : 1
},
"indexName" : "title_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"title" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"title" : [
"[\"标题9999\", \"标题9999\"]"
]
}
}
},
"rejectedPlans" : [ ]
},
"executionStats" : {
"executionSuccess" : true,
"nReturned" : 1,
"executionTimeMillis" : 1, //搜索时间为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" : {
"title" : 1
},
"indexName" : "title_1",
"isMultiKey" : false,
"multiKeyPaths" : {
"title" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"title" : [
"[\"标题9999\", \"标题9999\"]"
]
},
"keysExamined" : 1,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
"serverInfo" : {
"host" : "LAPTOP-H3U7J3BH",
"port" : 27017,
"version" : "4.0.10",
"gitVersion" : "c389e7f69f637f7a1ac3cc9fae843b635f20b766"
},
"ok" : 1
}
上面经过创建索引后再进行搜索时间明显减少,为1ms,后面再经过测试,也就是经过第二次,第三次进行搜索,时间减到了0
下面先删除升序索引,创建降序索引:
> db.first.dropIndex("title_1")
{ "nIndexesWas" : 2, "ok" : 1 }
> db.first.ensureIndex({title:-1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
> db.first.find({title:"标题9999"}).explain("executionStats")
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "test.first",
"indexFilterSet" : false,
"parsedQuery" : {
"title" : {
"$eq" : "标题9999"
}
},
"winningPlan" : {
"stage" : "FETCH",
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"title" : -1
},
"indexName" : "title_-1",
"isMultiKey" : false,
"multiKeyPaths" : {
"title" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"title" : [
"[\"标题9999\", \"标题9999\"]"
]
}
}
},
"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" : {
"title" : -1
},
"indexName" : "title_-1",
"isMultiKey" : false,
"multiKeyPaths" : {
"title" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"title" : [
"[\"标题9999\", \"标题9999\"]"
]
},
"keysExamined" : 1,
"seeks" : 1,
"dupsTested" : 0,
"dupsDropped" : 0,
"seenInvalidated" : 0
}
}
},
"serverInfo" : {
"host" : "LAPTOP-H3U7J3BH",
"port" : 27017,
"version" : "4.0.10",
"gitVersion" : "c389e7f69f637f7a1ac3cc9fae843b635f20b766"
},
"ok" : 1
}
这里用降序索引用时也是1ms,和用升序一样的用时,第二次及以后时间也会减少到0,
但是如果不建立索引,虽然也会根据搜索次数的增加而时间减少,但是会有下线,不会减少到0,
刚开始建立索引搜索的时候用时竟然是351ms,比不用索引大了10倍不止,虽然第二次搜索降为了0,但还是挺恐怖的,隔了一天我重新尝试,就是上面的这些了,显示用时才正常起来,索引第一次搜索比不用索引小很多,如果有知道原因的,大家可以评论一下,解决这个小bug