MongoDB索引

使用索引可以避免全表扫描,提高查询效率:
这里写图片描述
在MongoDB3.0之后使用totalDocsExamined 替代之前的”nscanned”。直接使用explain()还不行。
这里写图片描述

创建索引:
使用ensureIndex()创建索引。添加索引时,MongoDB不仅要更新文档,还要更新集合上的所有索引。限制每个集合上最多只能有64个索引。
索引建立在常用的查询字段,或者需要被优化、易造成瓶颈的查询。
这里写图片描述
上面返回的信息说明在新建索引之前,已经存在一个索引,这个索引就是”_id”。如果将集合中的文档都删除,但是索引并没有被删除,只有将集合删掉,索引才会被删除:
这里写图片描述

建立索引后,索引的值是按一定的顺序排列的。只有在首先使用索引键上进行排序,排序才能得到优化。
这里写图片描述
上面的结果按照age重新排序,并没有发挥索引值name的优势。

复合索引:查询中有多个排序方向或查询条件中有多个键,可以使用复合索引。它是建立在多个字段上的索引。
这里写图片描述
上面的索引包括age和name字段,每一个索引条目都指向文档的位置。上图中文档按照age升序排列,如果age相同,则按照name字段升序排列。

点查询:用于查找单个值,并进行排序:
这里写图片描述
建立索引时已经是排序了,索引再按照name值降序排列只需要逆序遍历就好,不用再进行排序,效率比较高。

多值查询:查找一定范围内的文档,使用索引字段进行查询,那结果就是按照索引的顺序进行升降序排列的。
这里写图片描述
上面的结果按照age值升序排列,当age值相同时,按照name值升序排列。发现name的值比较混乱。

对上面的查询按照name进行排序:
这里写图片描述
在默认情况下,name结果的值是无序的。当强制进行排序时,会对无序的结果在内存中强行进行排序,然后才能返回。所以,排序的效率不如上一个排序。

hint()函数:可以强制使用某个特定的索引。
这里写图片描述
强制使用某个索引时,也要先建立该索引。上图按照name升序排列。这样查询就不需要再进行内部排序了,但是age字段乱序,要找到指定范围内的age值,需要遍历整个集合,比较耗时。

但是如果只是限定查询结果的数量limit(),而不是查找所有的文档,使用这种索引可能会比较快,不需要再内存中排序。
这种形式可以简化为:{“sortKey”:1,”queryCriteria”:1}
将索引中第一个键作为排序,而第二个键作为查询条件。类似于上图的形式。

基于多个查询条件进行排序时,索引使用的方向与排序的方向相同就好,相互反转(在每个方向上乘以-1)的索引是等价的。例如{“age”:-1,”username”:1}与{“age”:1,”username”:-1}适用的查询是等价的。

覆盖索引:当一个索引包含用户请求的所有字段,可以认为这个索引覆盖了本次查询,没必要获取实际的文档。应该优先使用覆盖索引,将不必要的字段(”_id”,除非它是索引的一部分)排除掉。数组字段作为索引,它永远也无法实现覆盖索引。

隐式索引:如果拥有N个键组成的索引,那么同时得到所有这N个键的前缀组成的索引。比如:存在索引{“a”:1,”b”:1,”c”:1},那么会得到的索引包括:{“a”:1},{“a”:1,”b”:1},{“a”:1,”b”:1,”c”:1}。
只有这些使用索引前缀的查询才能得到优化,而这些键的任意子键所组成的索引并不一定可用。

对于一些低效率的操作符,比如”$exists”,”$ne”,”$not”,”$nin”。这些操作符可能要进行全表扫描。可以找到另一个能够使用索引的语句(eg,”_id”是唯一索引),查询语句中字段顺序无关紧要,MongoDB会自动找到可以使用索引的字段。这样可以将结果集的文档数量缩减一定的范围,再使用这些操作符会提高效率。
例如:db.test.find({“x”:{“$exists”:false},”_id”:{“$gt”:2}})

范围:设计基于多个字段的索引时,应该将会用于精确匹配的字段放在索引的前面,将用于范围匹配的字段放在最后。这样,可以先根据第一个字段进行精确匹配,然后再使用第二个索引在这个结果集内进行搜索。例如,存在这样的索引{“age”:1,”name”:1}。
在查询中find({age:34,”name”:{“$gt”:”user01”,”$lt”:”user05”}}),会根据第一个age字段精确匹配,在匹配后的结果集中进行范围匹配。
如果使用索引{“name”:1,age:1}时,上述查询会先查询name的范围,然后在范围内遍历查找age的值。这种索引效率没有第一种效率高。

创建索引时,字段顺序很重要,因为索引是根据该顺序在内存中排序的。但是在查询的时候,查询字段的顺序不太重要,MongoDB会自动找到索引的字段。

MongoDB中一次查询只能使用一个索引,如果存在两个索引,MongoDB会使用其中的一个索引,除非强制使用某个索引。但是使用” or"使使使" in”,而不是” or"" or”查询会从结果集中移除重复的文档,”$in”查询无法控制文档返回的顺序。

MongoDB允许深入文档内部,对嵌套字段和数组建立索引。
(1)索引嵌套文档
可以在嵌套文档的键上建立索引,方式与正常的键是一样的。
这里写图片描述
对嵌套文档本身(“loc”)建立索引,与对嵌套文档某个字段(“loc.city”)建立的索引是不同的。对整个子文档建立索引,只会提高整个子文档的查询速度。
只有在进行与子文档字段顺序完全匹配的子文档查询时,例如:
find({“loc”:{“id”:”192.22.23.22”,”city”:”hangzhou”,state:”USA”}}),查询优化器才会使用”loc”上的索引,对于find({“loc.city”:”hangzhou”})是无法使用该索引的。

(2)索引数组
对数组建立索引,实际是对数组中的每一个元素建立索引条目,因此数组索引的代价比单值索引高。
这里写图片描述
无法将整个数组作为一个实体建立索引,只能对数组中的每个元素建立索引,而不是对数组本身建立索引。对”comments”建立索引实际是对数组元素建立索引。
在数组上建立索引不包含位置信息,也就是不能使用 “comments.2”建立索引。但是可以对某个特定条目进行索引:ensureIndex({“comments.10.date”:1}),这种情况下,只有精确匹配第11个数组元素时这个索引才有用。

一个索引中数组字段最多只有一个,避免在多键索引中引起索引条目过多增长。

对于某个索引的键,如果该键在某个文档中是一个数组,那么这个索引就会被标记为多键索引,比如“comments”字段。索引只要被标记为多键索引,就无法成为非多键索引,只能删除该索引。

索引基数:集合中某个字段拥有不同值得数量。比如,”gender”字段只有两个不同的值”男”和”女”;”name”字段可能在每个文档中的值都不一样。这说明基数很高。
一个字段的基数越高,这个键上的索引越有用。因为索引能够迅速将搜索范围缩小到比较小的结果集。
应该在基数比较高的键上建立索引,或者至少应该把基数较高的键放在符合索引的前面(低基数的键之前)。

结果集在原集合中所占的比例越大,索引的速度就越慢,因为使用索引需要进行两次查找:一次查找索引条目;一次根据索引指针去查找相应的文档。

唯一索引
唯一索引可以确保集合的每一个文档的指定键都有唯一值。
这里写图片描述
文档中的”_id”键就是唯一索引。该唯一索引不能被删除,而其他唯一索引是可以删除的。
如果对某个键建立唯一索引,但文档中没有改键,索引会将其作为null存储。但是如果插入多个缺少该索引键的文档,会导致插入失败。因为已经存在一个该索引键值为null的文档。

复合唯一索引
创建复合唯一索引,单个键的值可以相同,但是所有键的组合值必须是唯一的。
这里写图片描述

对于集合中已经有重复值,再创建唯一索引就会失败。

稀疏索引
如果希望唯一索引只对包含相应键的文档生效,对于一个可能存在也可能不存在的字段,只有当它存在时,它的值必须是唯一的。MongoDB中的稀疏索引只是不需要将每个文档都作为索引条目。
这里写图片描述
将”unique”去掉,可以创建一个非唯一的稀疏索引。
这里写图片描述

查看指定集合上的所有索引:
这里写图片描述
指定索引的名字:
这里写图片描述
删除不必要的索引:参数是索引的名称
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值