学习mongodb,体会mongodb的每一个使用细节,欢迎阅读威赞的文章。这是威赞发布的第80篇mongodb技术文章,欢迎浏览本专栏威赞发布的其他文章。如果您认为我的文章对您有帮助或者解决您的问题,欢迎在文章下面点个赞,或者关注威赞。谢谢。
前面的文档当中,我们重点介绍了mongodb数据更新update中各种各样的操作符。有兴趣的小伙伴们可以查看本专栏里的相关文章。这篇文章,结合官方文档,探讨一下使用索引进行查询优化。
概述
为集合建立合适的索引,能够有效的减少查询操作时扫描数据的数量 ,从而提高查询效率,简化了mongodb内部查询工作。如原来的某个查询需要进行全表扫描。当集合中有1000条数据时,可能需要逐一扫描这1000条数据,才可以返回查询结果。而当为查询字段添加索引后,通过索引,直接定位到查询结果,可能会极大的减少扫描文档数据的数量。
为读取操作添加索引
当用户建立查询语句,计划通过指定字段或几个字段查询数据时,在指定字段的索引或者几个字段的复合索引能够避免对集合进行全表扫描。
如一个针对表inventory的查询,要求使用字段type作为过滤条件,type是用户指定的一个数值
var typeValue = <someUserInput>;
db.inventory.find( {type: typeValue});
为了提高这个针对集合inventory查询的性能,在集合inventory创建一个type字段的索引。使用db.collection.createIndex()方法创建。这个索引,能够避免查询整个集合来返回数据。
db.inventory.createIndex({type: 1})
用户可以通过分析执行计划,来确定mongodb是否使用当前索引。
除了提高查询效率以外,索引还可以改善排序操作的效率并能够提过存储空间使用率。
查询操作过滤度
查询操作过滤度表示了查询操作中使用的过滤词排除或者过滤文档的优良程度。查询操作过滤度能够决定该查询是否使用索引。高过滤度查询,能够匹配出更小范围的文档数据。如针对_id字段等等值查询就具备非常高的查询操作过滤度。它几乎可以匹配到唯一的文档数据。相反,低过滤度的查询会匹配集合中更多百分比的数据,几乎不能使用索引。
例如不等操作nin和ne就不是高过滤度查询操作,这两个查询操作经常会匹配到集合中大部分的数据。因此在大多数查询当中,带有nin和ne操作的查询,使用索引查询效率,不会比全表扫描高多少。
而对于正则表达式的查询过滤度,还与正则表达式本身相关。
索引覆盖查询
索引覆盖查询只完全通过索引过滤数据并且使用索引中的字段来返回结果而不需要查询文档数据的查询。同时满足下面三个条件,就可以所该索引覆盖了查询
- 查询中所有查询字段都是索引的一部分
- 查询返回字段也包含在该索引当中
- 查询当中过滤字段没有对null的过滤(如{"field": null}或者{"field": {$eq: null}})。
例如在集合inventory中创建字段type和item的索引
db.inventory.createIndex({type: 1, item:1})
该索引覆盖了下面的查询操作。只通过type和item字段过滤数据,只返回item字段
db.inventory.find(
{type:"food", item: /^c/},
{item:1, _id:0}
)
因为该索引中并不包含_id字段,因此查询返回字段中,需要显示的把_id字段排除。
嵌入式文档索引覆盖查询
同样,索引覆盖查询也适用于嵌入式文档。例如,集合userdata中有下面的数据
{ _id:1, user: { login: "tester"}}
为该集合建立索引
db.userdata.createIndex({"user.login":1})
该索引可以覆盖下面的查询
db.userdata.find( {"user.login": "tester"}, {"user.login": 1, _id: 0})
多键索引覆盖查询
多键索引能够覆盖针对索引中非数组字段的查询。不能覆盖带有数组字段的查询。
索引覆盖查询性能
因为索引当中已经包含了查询中所需要的所有字段和返回字段 ,mongodb可以只通过索引返回查询结果。只通过索引的查询效率,比其他任何索引外查询的效率都要高。因为索引通常保存在内存当中或顺序的保存在磁盘上,而且会比索引依赖的文档小。
索引查询优化限制
- 地理信息索引不支持索引覆盖查询
- 多键查询不能覆盖带有数组字段的查询
- 在分片集中,包含分片key的索引才能支持索引覆盖查询
当然用户可以查看执行计划,确当该查询是否是索引覆盖查询。