MongoDB基础教程系列--第六篇 MongoDB 索引

时间:2023-12-04 21:17:50

返回目录

使用索引可以大大提高文档的查询效率。如果没有索引,会遍历集合中所有文档,才能找到匹配查询语句的文档。这样遍历集合中整个文档的方式是非常耗时的,特别是处理大数据时,耗时几十秒甚至几分钟都是有可能的。

创建索引

MongoDB 中,使用 ensureIndex() 方法创建索引。

格式

db.COLLECTION_NAME.ensureIndex({KEY:1})

其中,KEY表示要创建索引的字段名称,1 表示按升序排列字段值。-1 表示按降序排列。

范例

1、给 user 集合中 name 字段添加索引

>db.user.ensureIndex({"name":1})
>

MongoDB 中用 db.collection.getIndexes() 方法查询集合中所有的索引,我们查询一下 user 中所有的索引。

>db.user.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "liruihuan.user"
},
{
"v" : 2,
"key" : {
"age" : 1
},
"name" : "name_1",
"ns" : "liruihuan.user"
}
]

我们发现 user 中有两个索引,其中索引 "_id_" 是我们创建 user 集合时,MongoDB 自动生成的索引。第二个索引就是我们刚才创建的索引,其中,name 值"name_1"表示索引名称,MongoDB 会自动生成的索引名称。当然,我们也可以自己指定索引的名称。

2、给 user 集合中 age 字段添加索引,并指定索引名称为 "index_age_esc"。

>db.user.ensureIndex({"age":1},{name:"index_age_esc"})
>db.user.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "liruihuan.user"
},
{
"v" : 2,
"key" : {
"age" : 1
},
"name" : "index_age_esc",
"ns" : "liruihuan.user"
}
]

指定索引名称用到的 name 参数,只是 ensureIndex() 方法可接收可选参数的其中一个,下表列出了 ensureIndex() 方法可接收的参数

Parameter Type Description
background 布尔值 建索引过程会阻塞其它数据库操作,background可指定以后台方式创建索引,即增加 "background" 可选参数。 "background" 默认值为false
unique 布尔值 建立的索引是否唯一。指定为true创建唯一索引。默认值为false.
name 字符串 索引的名称。如果未指定,MongoDB的通过连接索引的字段名和排序顺序生成一个索引名称。
dropDups 布尔值 在建立唯一索引时是否删除重复记录,指定 true 创建唯一索引。默认值为 false.
sparse 布尔值 对文档中不存在的字段数据不启用索引;这个参数需要特别注意,如果设置为true的话,在索引字段中不会查询出不包含对应字段的文档.。默认值为 false.
expireAfterSeconds 整型 指定一个以秒为单位的数值,完成 TTL设定,设定集合的生存时间。
v 索引版本 索引的版本号。默认的索引版本取决于mongod创建索引时运行的版本。
weights 文档(document) 索引权重值,数值在 1 到 99,999 之间,表示该索引相对于其他索引字段的得分权重。
default_language 字符串 对于文本索引,该参数决定了停用词及词干和词器的规则的列表。 默认为英语
language_override 字符串 对于文本索引,该参数指定了包含在文档中的字段名,语言覆盖默认的language,默认值为 language.

唯一索引

MongoDB和关系型数据库一样都可以建立唯一索引,重复的键值就不能重新插入了,MongoDB 用 unigue 来确定建立的索引是否为唯一索引,true 表示为唯一索引,下面给 user 集合的 name 字段指定唯一索引

>db.user.ensureIndex({"name":1},{unique:true})

> db.user.find()
{ "_id" : ObjectId("58e1d2f0bb1bbc3245fa754b"), "name" : "liruihuan", "age" : 18,"sex":"man" } >db.user.insert({"name":"liruihuan","age":18})
E11000 duplicate key error collection: liruihuan.user index: name_1 dup key: { : \"liruihuan\"

可以看出,创建了唯一索引的字段,是不能再插入 "liruihuan" 的 name 值的。

复合索引

ensureIndex() 方法中你也可以设置使用多个字段创建索引

范例

>db.user.ensureIndex({"name":1,"age":1})
>db.user.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "liruihuan.user"
},
{
"v" : 2,
"key" : {
"name" : 1,
"age" : 1
},
"name" : "name_1_age_1",
"ns" : "liruihuan.user"
}
]

删除索引

MongoDB 用dropIndex() 方法删除索引

格式

db.COLLECTION_NAME.dropIndex()

注:dropIndex() 方法可根据指定的索引名称或索引文档删除索引(_id上的默认索引除外)

范例

我们用两种方式删除掉 user 中 name 字段上的索引

>db.user.dropIndex("name_1")     #根据索引名称删除索引
>db.user.dropIndex({"name":1}) #根据索引文档删除索引

还可以用 dropIndexes() 删除集合中所有索引(_id上的默认索引除外)

>db.user.dropIndexes()

查询分析

查询分析是查询语句性能分析的重要工具。

MongoDB 中查询分析用 explain() 和 hint() 方法

范例

我们向集合 user 中插入20万条数据,利用 explain() 查询建立索引前后,执行时间的比较,来看看建立索引对查询效率的提高程度。

第一步,向 user 中插入20万条数据

>db.user.remove({})
>for(var i = 0; i <200000; i++){db.user.insert({"name":"lrh"+i,"age":18})}

第二步,删除 user 集合中字段 name 上的索引,然后查询 name = "lrh100000",利用explain("executionStats")查询此时执行的时间。说明:MongoDB explain() 方法在3.0以后版本中发生了很大改变,3.0之前版本直接用explain()就可以,不用传参数,如果想详细了解,请访问官网

>db.user.dropIndexes()      #删除所有索引
db.user.find({"name":"lrh100000"}).explain("executionStats")
{
"queryplanner" : {
......
},
"executionStats" : {
"executionTimeMillis" : 109
......
}
}

explain.executionStats.executionTimeMillis:表示查询所用的时间,单位是毫秒。

我们可以清楚的看出,没用索引查询用到的时间是 109 毫秒。

第三步,给 user 集合中 name 字段添加索引,然后再查询同一个条件,看执行查询所用了多久时间。

>db.user.ensureIndex({"name":1})
>db.user.find({"name":"lrh100000"}).explain("executionStats")
{
"queryplanner" : {
"winningPlan" : {
"inputStage" : {
"indexName" : "name_1"
......
}
.......
}
.......
},
"executionStats" : {
"executionTimeMillis" : 1
......
}
}

如果用到了索引,explain() 方法会返回 winningPlan,标识用到的索引名称 indexName

我们可以清楚到处,用了索引,执行时间只有 1 毫秒,可以看出,查询效率的提高可不是一星半点。

注:如果想更详细的了解 explain() 返回的参数,可以去官网看一下

第四步,这一步我们重点看看 hint() 方法的用法。hint() 方法用来强制 MongoDB 使用一个指定的索引。

我们给 user 再添加一个 {"name":1, "age":1},利用 explain() 方法,看一下用到了哪个索引。

>db.user.ensureIndex({"name":1, "age":1})
>db.user.find({"name":"lrh100000"}).explain("executionStats")
{
"queryplanner" : {
"winningPlan" : {
"inputStage" : {
"indexName" : "name_1_age_1"
......
}
.......
}
.......
}
......
}

可以看出,此时用到的索引是 "name_1_age_1",如果我们想用索引 "name_1",就可以用 hint() 方法指定。

>db.user.find({"name":"lrh100000"}).hint({"name":1}).explain("executionStats")
{
"queryplanner" : {
"winningPlan" : {
"inputStage" : {
"indexName" : "name_1"
......
}
.......
}
.......
}
......
}

业精于勤,荒于嬉;行成于思,毁于随。

如果你觉得这篇文章不错或者对你有所帮助,可以通过右侧【打赏】功能,给予博主一点点鼓励和支持