1. 如果没有索引,MongoDB执行全集合扫描,但如果存在适当的索引,MongoDB可以使用该索引限制查询的文档数,索引方式为 B树索引<br />官方文档:[https://docs.mongodb.com/manual/indexes/](https://docs.mongodb.com/manual/indexes/)

索引类型:

单字段索引:

在文档的单个字段上创建用户定义的升序/降序索引,称为单字段索引,对于单个字段索引和排序操作,索引键的排序顺序(即升序或降序)并不重要,因为MongoDB可以在任何方向上遍历索引。升序为1,降序为-1
如果是嵌入式字段,如果只搜索部分字段,则需要先创建搜索部分字段的索引才能使用,直接创建嵌入字段的索引是无效的
image.png
例如有以下数据:

  1. db.helloIndex.insert(
  2. {
  3. "_id": ObjectId("570c04a4ad233577f97dc459"),
  4. "score": 1034,
  5. "location": { state: "NY", city: "New York" }
  6. }
  7. )

如果有进行内部字段 state 或 city 的搜索,需要对内部字段进行索引:

  1. db.helloIndex.createIndex( { "location.state": 1 } )
  2. db.helloIndex.createIndex( { "location.city": 1 } )
  3. #搜索案例:
  4. db.helloIndex.find( { "location.state": "NY" } )
  5. db.helloIndex.find( { "location.city": "New York" } )

如果是对整个字段进行搜索,直接对其嵌入字段建立索引即可:

  1. db.helloIndex.createIndex( { location: 1 } )
  2. #搜索案例:
  3. db.helloIndex.find( { location: { city: "New York", state: "NY" } } )

复合索引:

还支持多个字段的用户定义索引,即复合索引,但复合索引的使用必须包含前缀
例如建立 ABC 三个字段的复合索引,支持 A、AB、ABC、AC调用索引进行查询,而B、BC这种非A开头的查询将无法调用索引
复合索引中列出的字段顺序具有重要意义。例如,如果复合索引由 { userid: 1, score: -1 } 组成,则索引首先按userid正序排序,然后在每个userid的值内,再在按score倒序排序
image.png

其他索引(了解):

地理空间索引:为了支持对地理空间坐标数据的有效查询,MongoDB提供了两种特殊的索引:返回结果时使用平面几何的二维索引和返回结果时使用球面几何的二维球面索引。

文本索引:支持在集合中搜索字符串内容。这些文本索引不存储特定于语言的停止词(例如“the”、“a”、“or”),而将集合中的词作为词干,只存储根词。

哈希索引:为了支持基于散列的分片,MongoDB提供了散列索引类型,它对字段值的散列进行索引。这些索引在其范围内的值分布更加随机,但只支持相等匹配,不支持基于范围的查询。

索引管理:

查看索引:

查看目标集合中的索引情况

  1. db.集合名.getIndexes()
  1. ![image.png](https://cdn.nlark.com/yuque/0/2021/png/21405095/1625639650773-77cd26f2-c578-43c3-ba56-f33b47e7f20a.png#clientId=u07643d5f-0dcc-4&from=paste&height=30&id=u1c623a23&margin=%5Bobject%20Object%5D&name=image.png&originHeight=41&originWidth=578&originalType=binary&ratio=1&size=3657&status=done&style=stroke&taskId=uad1d8d6e-d086-462b-81b6-344cc8139ac&width=423)<br />**默认创建一个为 _id 的索引**

创建索引:

索引名在未指定的情况下会自动生成,若要指定名称,添加name参数即可

唯一性:
单字段索引 + 唯一限制:如果新增的文档不包含该索引字段,只有第一条没有该字段的数据可以被保存(存入Null值)
复合索引 + 唯一限制:不同文档之间对应复合索引字段的数据组合不能重复

稀疏性:
只包含文档中具有该索引字段的数据,没有该索引字段的数据不会被添加到稀疏性索引中。好处是节约索引所占用的储存空间。
单字段索引 + 唯一性 + 稀疏性:将允许保存多篇缺失索引值的数据
复合索引 + 唯一性 + 稀疏性:只有缺失复合索引中的所有字段的文档数据才不会被加入到索引中

指定过期时间:
针对日期字段或包含日期元素的数组字段,可以创建设置了过期时间的索引来自动删除字段值操作生存时间的文档数据
当索引键是包含日期元素的数组字段时,数组中最小的日期将被用来计算文档是否过期;复合索引不具备过期时间特性
数据库使用后台线程来讲错和删除过期的文档数据,该操作可能有延迟

  1. db.集合名.createIndex({字段名:1/-1}) 创建单字段索引
  2. db.集合名.createIndex({字段名:1/-1},{"name":"自定义索引名"}) 创建自定义名称的单字段索引
  3. db.集合名.createIndex({字段名:1/-1}{字段名:1/-1}) 创建复合索引
  4. db.集合名.createIndex({字段名:1/-1},{unique:true}) 创建唯一索引(字段必须无重复值)
  5. db.集合名.createIndex({字段名:1/-1},{sparse:true}) 创建稀疏性索引
  6. db.集合名.createIndex({字段名:1/-1},{expireAfterSeconds:秒数}) 对字段名(时间类型)创建具有指定秒数过期时间的索引

例如对 content 字段创建一个索引:

  1. db.comment.createIndex({content:1}) 单字段索引的升序/降序指定无意义

例如对 userid 字段创建自定义名称的索引:

  1. db.comment.createIndex({userid:1},{name:userIndex})

image.png
自定义索引名称成功

例如对 likenum 升序 + userid 降序的复合索引:

  1. db.helloIndex.createIndex({likenum:1,userid:-1})

例如对 time 创建一个20秒过期时间的索引并保存一条数据:

  1. db.helloIndex.createIndex({time:1},{expireAfterSeconds:20})
  2. #该数据20秒后会自动删除
  3. db.helloIndex.insertOne({time:new Date(),name:"ddd"})

删除索引:

输入索引的创建规则或者名称进行删除

  1. db.集合名.dropIndex({索引字段排序条件}) 根据创建规则删除索引
  2. db.集合名.dropIndex({索引名称}) 根据名称删除索引
  3. db.集合名.dropIndexes() 删除除 _id 以外的所有索引

例如删除刚才创建的 likenum 升序 + userid 降序的复合索引:

  1. db.comment.dropIndex({likenum:1,userid:-1}) 通过索引条件删除

例如删除刚才创建的 userid 字段创建自定义名称的索引:

  1. db.comment.dropIndex({userid:1}) 通过索引条件删除
  2. db.comment.dropIndex("userIndex") 通过索引名称删除

索引使用:

如果查询的字段没有创建索引将会进行全行扫描,使用 MySQL 一样的 explain 查看SQL执行计划

  1. db.集合名.find(查询条件).explain()

例如对未建立索引的 userid 进行查询:
image.png
image.png
走的是全行扫描

对 userid 建立索引后再次执行查询:
image.png
image.png
已使用索引进行抓取查询、

当查询条件和查询的投影仅包含索引字段时,MongoDB直接从索引返回结果,而不扫描任何文档或将文档带入内存
image.png
由于 userid 为单字段索引,在只返回 userid 字段的情况下,MongoDB直接从索引返回结果