虽然MongoDB查询优化器一般工作的很不错,但是也可以使用 hint 来强制 MongoDB 使用一个指定的索引。
这种方法某些情形下会提升性能。 一个有索引的 collection 并且执行一个多字段的查询(一些字段已经索引了)。

(1) 复合索引创建语法
db.collection.createIndex( { : , : , … } )
同创建单键(列)索引一样,索引创建时需要指定每一个键索引的顺序
多个键直接用逗号分隔

(2) 复合索引的特性
1.复合索引可以支持要求匹配多个键的查询
2.复合索引每一个键的顺序非常重要,这将决定该索引在查询过程中能否被使用到
3.复合索引支持前导(缀)列索引查询
4.不能够创建基于哈希索引类型的复合索引
5.任意复合索引字段不能超过31个

(3) 索引性能对比
你可以使用 hint() 方法结合 explain() 方法来对查询中的多个索引的性能进行手工对比。

在使用复合索引的时候,字段的顺序很重要(注意是索引中的顺序,而非查询中出现的顺序)。

比如,创建下面两个复合索引。第一个索引把 quantity 字段放在前面,而第二个字段把 type 字段放前:

为了方便演示,我们做两组复合索引,比如这次我们在quality和type上构建一下:

mongoTemplate聚会查询 mongodb聚合查询索引性能分析_查询优化


针对quantity是一个范围,而type是一个定值的情况下,我们强制mongodb去使用quantity开头的复合索引,从而强制mongodb give up 那个以{type:1,quantity:1}的复合索引,如下图:

mongoTemplate聚会查询 mongodb聚合查询索引性能分析_mongoTemplate聚会查询_02


上图中,可以看到MongoDB扫描了6个索引键(executionStats.totalKeysExamined)以及2个匹配文档(executionStats.nReturned)。再对第二个索引在该查询上的效果进行评估:

mongoTemplate聚会查询 mongodb聚合查询索引性能分析_字段_03


MongoDB 扫描了 2 个索引键(executionStats.totalKeysExamined)以返回 2 个匹配的文档(executionStats.nReturned)。

显而易见,对于上述查询,复合索引 { type: 1, quantity: 1 } 比 { quantity: 1, type: 1 } 更高效。

indexBounds:当前查询具体使用的索引。
分析index与document扫描数与查询返回条目数
这里主要谈3个返回项,nReturned,totalKeysExamined与totalDocsExamined,分别代表该条查询返回的条目、索引扫描条目和文档扫描条目。
理想状态如下:
nReturned=totalKeysExamined & totalDocsExamined=0 (cover index,仅仅使用到了index,无需文档扫描,这是最理想状态。)
或者
nReturned=totalKeysExamined=totalDocsExamined(需要具体情况具体分析)(正常index利用,无多余index扫描与文档扫描。)检查的键数与返回的文档数相匹配,这意味着mongod只需检查索引键即可返回结果。mongod不必扫描所有文档,只有三个匹配的文档被拉入内存。 这个查询结果是非常高效的。
如果有sort的时候,为了使得sort不在内存中进行,我们可以在保证nReturned=totalDocsExamined的基础上,totalKeysExamined可以大于totalDocsExamined与nReturned,因为量级较大的时候内存排序非常消耗性能。

如果查询条件中的键值顺序和复合索引中的创建顺序不一致的话,MongoDB可以智能的帮助我们调整该顺序,以便使复合索引可以为查询所用
MongoDB在检索之前将会动态的调整查询条件文档的顺序,以使该查询可以用到刚刚创建的复合索引
hint函数会返回游标,我们可以在游标上调用explain查看索引的使用情况!99%的情况,我们没有必要通过hint去强制使用某个索引,MongoDB的查询优化器非常智能,绝对能帮助我们使用当前已有索引中的最佳的索引去进行查询!
通过hint去强制使用某个索引这种方法某些情形下会提升性能。 一个有索引的 collection 并且执行一个多字段的查询(一些字段已经索引了)可以用。

>db.users.find({gender:"M"},{user_name:1,_id:0}).hint({gender:1,user_name:1})

文档连接:http://www.runoob.com/mongodb/mongodb-analyzing-queries.html

API原文链接:https://docs.mongodb.com/manual/tutorial/analyze-query-plan/

(4) 何时该用索引
提取较小的子数据集时,索引非常有效(所以才有了分页)。也有一些查询不使用索引会更快。结果集在原集合中所占的比例越大,查询效率越慢。因为使用索引需要进行两次查找:一次查找索引条目,一次根据索引指针去查找相应的文档。而全表扫描只需要进行一次查询。在最坏的情况,使用索引进行查找次数会是全表扫描的两倍。效率会明显比全表扫描低。
可惜并没有一个严格的规则可以告诉我们,如果根据索引大小、文档大小来判断什么时候索引很有用,一般来说,如果查询需要返回集合内30%的文档(或者更多),那就应该测试全表扫描和走索引查询那个速度比较快。这个数字也会在2%~60%之间进行波动。
这个时候可以使用hint({"$natural":true})强制查询走全表扫描。