在 MongoDB 中使用覆盖索引查询
你可能听说过列索引是通过最大限度地减少查询所需的磁盘访问次数来优化查询性能的好方法。MongoDB 有一个字段索引的特定应用程序,称为覆盖索引查询(Covered Queries),其中查询的所有列都被进行索引。因为 MongoDB 不必检查除索引之外的任何文档,所以覆盖索引查询非常快。在今天的文章中,我们将学习如何使用覆盖索引查询更快地查询数据。
覆盖索引查询的定义
在引言段落中,我们提到了对覆盖索引查询的所有列进行索引。除此之外,具体而言,覆盖索引查询是以下的查询:
- 查询所有的字段是索引的一部分。
- 查询的所有返回字段都在同一个索引中。
在幕后 MongoDB 无需实际查看文档内部就能匹配查询条件和返回使用相同索引的结果。由于索引存在于 RAM 中,因此从索引中获取数据比通过扫描文档读取数据要快得多。
我们现在知道了什么是覆盖查询,就开始编写一个吧!
创建索引
我们将在 Sakila 示例数据库的 film 表运行查询。它包含许多与虚构电影有关的字段。这些包括标题、描述、发行年份,以及租赁信息,如价格和租赁期限。这是在 Navicat for MongoDB 以树视图显示的文档::
让我们以 title 和 release_year 字段创建一个复合索引:
- 点击主工具栏上的大“索引”按钮,然后点击对象工具栏上的“新建索引”按钮:
在“常规”选项卡, - 从“集合名”下拉列表中选择“film”。
- 在“索引版本:”下面,从“字段”下拉列表中选择“title”,然后从“类型”下拉列表中选择“ASC”。
- 然后,点击屏幕底部的加号(+)按钮添加第二个字段:
- 从“字段”下拉列表中选择“release_year”,然后再从“类型”下拉列表中选择“ASC”。
- 现在,点击“文本”选项卡,然后在“权重”标题下,按照与上面相同的过程从“字段”下拉列表中选择那两个字段,并指定权重为 1:
- 最后,点击“保存”按钮,并输入“film_title_year”索引名。
运行覆盖索引查询
对索引字段运行查询:
- 点击主工具栏上的大“查询”按钮,然后点击对象工具栏上的“新建查询”按钮。
- 在查询编辑器中,键入以下的 find() 调用:
db.film.find({title:{$regex : ".*AGENT.*"}},{title:1,release_year:1,_id:0}) - 点击“运行”按钮以运行查询。结果如下:
你可以从主菜单中选择“查询”>“解释”以查看查询的运行统计信息:
总结
如果你希望提升查询速度,请考虑使用覆盖索引查询。它们的速度非常快,因为 MongoDB 只需要检查存在于 RAM 中的索引文档。
官方的MongoDB的文档中说明,覆盖查询是以下的查询:
- 所有的查询字段是索引的一部分
- 所有的查询返回字段在同一个索引中
由于所有出现在查询中的字段是索引的一部分, MongoDB 无需在整个数据文档中检索匹配查询条件和返回使用相同索引的查询结果。
因为索引存在于RAM中,从索引中获取数据比通过扫描文档读取数据要快得多。
为了测试盖索引查询,使用以下 mycol 集合:
{ "_id" : 1, "name" : "tom", "sex" : "男", "score" : 100, "age" : 34 }
{ "_id" : 2, "name" : "jeke", "sex" : "男", "score" : 90, "age" : 24 }
{ "_id" : 3, "name" : "kite", "sex" : "女", "score" : 40, "age" : 36 }
{ "_id" : 4, "name" : "herry", "sex" : "男", "score" : 90, "age" : 56 }
{ "_id" : 5, "name" : "marry", "sex" : "女", "score" : 70, "age" : 18 }
{ "_id" : 6, "name" : "john", "sex" : "男", "score" : 100, "age" : 31 }
我们在 users 集合中创建联合索引,字段为 sex 和 score :
db.mycol.ensureIndex({sex : 1, score : 1})
现在,该索引会覆盖以下查询:
db.mycol.find({sex: '男'},{name : 1, _id : 0})
也就是说,对于上述查询,MongoDB的不会去数据库文件中查找。相反,它会从索引中提取数据,这是非常快速的数据查询。
由于我们的索引中不包括 _id 字段,_id在查询中会默认返回,我们可以在MongoDB的查询结果集中排除它。
下面的实例没有排除_id,查询就不会被覆盖:
db.mycol.find({sex: '男'},{name : 1})
最后,如果所有索引字段是一个数组,不能使用覆盖索引查询。
posted on 2021-02-26 15:58 ExplorerMan 阅读(201) 评论(0) 编辑 收藏 举报