MongoDB基础教程系列--第六篇 MongoDB 索引
使用索引可以大大提高文档的查询效率。如果没有索引,会遍历集合中所有文档,才能找到匹配查询语句的文档。这样遍历集合中整个文档的方式是非常耗时的,特别是处理大数据时,耗时几十秒甚至几分钟都是有可能的。
创建索引
MongoDB 中,使用 ensureIndex() 方法创建索引。
格式
1 | db.COLLECTION_NAME.ensureIndex({ KEY :1}) |
其中,KEY表示要创建索引的字段名称,1 表示按升序排列字段值。-1 表示按降序排列。
范例
1、给 user 集合中 name 字段添加索引
1 2 | >db. user .ensureIndex({ "name" :1}) > |
MongoDB 中用 db.collection.getIndexes() 方法查询集合中所有的索引,我们查询一下 user 中所有的索引。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | >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"。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | >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 字段指定唯一索引
1 2 3 4 5 6 7 | >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() 方法中你也可以设置使用多个字段创建索引
范例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | >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() 方法删除索引
格式
1 | db.COLLECTION_NAME.dropIndex() |
注:dropIndex() 方法可根据指定的索引名称或索引文档删除索引(_id上的默认索引除外)
范例
我们用两种方式删除掉 user 中 name 字段上的索引
1 2 | >db. user .dropIndex( "name_1" ) #根据索引名称删除索引 >db. user .dropIndex({ "name" :1}) #根据索引文档删除索引 |
还可以用 dropIndexes() 删除集合中所有索引(_id上的默认索引除外)
1 | >db. user .dropIndexes() |
查询分析
查询分析是查询语句性能分析的重要工具。
MongoDB 中查询分析用 explain() 和 hint() 方法
范例
我们向集合 user 中插入20万条数据,利用 explain() 查询建立索引前后,执行时间的比较,来看看建立索引对查询效率的提高程度。
第一步,向 user 中插入20万条数据
1 2 | >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()就可以,不用传参数,如果想详细了解,请访问官网。
1 2 3 4 5 6 7 8 9 10 11 | >db. user .dropIndexes() #删除所有索引 db. user .find({ "name" : "lrh100000" }).explain( "executionStats" ) { "queryplanner" : { ...... }, "executionStats" : { "executionTimeMillis" : 109 ...... } } |
explain.executionStats.executionTimeMillis:表示查询所用的时间,单位是毫秒。
我们可以清楚的看出,没用索引查询用到的时间是 109 毫秒。
第三步,给 user 集合中 name 字段添加索引,然后再查询同一个条件,看执行查询所用了多久时间。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | >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() 方法,看一下用到了哪个索引。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | >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() 方法指定。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | >db. user .find({ "name" : "lrh100000" }).hint({ "name" :1}).explain( "executionStats" ) { "queryplanner" : { "winningPlan" : { "inputStage" : { "indexName" : "name_1" ...... } ....... } ....... } ...... } |
业精于勤,荒于嬉;行成于思,毁于随。
如果你觉得这篇文章不错或者对你有所帮助,可以通过右侧【打赏】功能,给予博主一点点鼓励和支持
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?