Mongodb 为什么Mongo提示会使查询运行速度提高10倍?

Mongodb 为什么Mongo提示会使查询运行速度提高10倍?,mongodb,indexing,hint,Mongodb,Indexing,Hint,如果我使用explain()从shell运行mongo查询,获取所用索引的名称,然后再次运行相同的查询,但是使用hint()指定要使用的相同索引,explain计划中的“millis”字段会显著减少 比如说 没有提供任何提示: >>db.event.find({ "type" : "X", "active" : true, "timestamp" : { "$gte" : NumberLong("1317498259000") }, "count" : { "$gte" : 0 }

如果我使用explain()从shell运行mongo查询,获取所用索引的名称,然后再次运行相同的查询,但是使用hint()指定要使用的相同索引,explain计划中的“millis”字段会显著减少

比如说

没有提供任何提示:

>>db.event.find({ "type" : "X", "active" : true, "timestamp" : { "$gte" : NumberLong("1317498259000") }, "count" : { "$gte" : 0 } }).limit(3).sort({"timestamp" : -1 }).explain();

{
    "cursor" : "BtreeCursor my_super_index",
    "nscanned" : 599,
    "nscannedObjects" : 587,
    "n" : 3,
    "millis" : 24,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : true,
    "indexOnly" : false,
    "indexBounds" : { ... }
} 
>>db.event.find({ "type" : "X", "active" : true, "timestamp" : { "$gte" : NumberLong("1317498259000") }, "count" : { "$gte" : 0 } }).limit(3).sort({"timestamp" : -1 }).hint("my_super_index").explain();

{
    "cursor" : "BtreeCursor my_super_index",
    "nscanned" : 599,
    "nscannedObjects" : 587,
    "n" : 3,
    "millis" : 2,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : true,
    "indexOnly" : false,
    "indexBounds" : { ... }
} 
提供的提示:

>>db.event.find({ "type" : "X", "active" : true, "timestamp" : { "$gte" : NumberLong("1317498259000") }, "count" : { "$gte" : 0 } }).limit(3).sort({"timestamp" : -1 }).explain();

{
    "cursor" : "BtreeCursor my_super_index",
    "nscanned" : 599,
    "nscannedObjects" : 587,
    "n" : 3,
    "millis" : 24,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : true,
    "indexOnly" : false,
    "indexBounds" : { ... }
} 
>>db.event.find({ "type" : "X", "active" : true, "timestamp" : { "$gte" : NumberLong("1317498259000") }, "count" : { "$gte" : 0 } }).limit(3).sort({"timestamp" : -1 }).hint("my_super_index").explain();

{
    "cursor" : "BtreeCursor my_super_index",
    "nscanned" : 599,
    "nscannedObjects" : 587,
    "n" : 3,
    "millis" : 2,
    "nYields" : 0,
    "nChunkSkips" : 0,
    "isMultiKey" : true,
    "indexOnly" : false,
    "indexBounds" : { ... }
} 
唯一的区别是“毫秒”场

有人知道为什么吗


更新:“选择要使用的索引”并不能解释这一点,因为据我所知,mongo每次运行X(100?)都会选择索引,所以它应该与hint next(X-1)运行一样快

mongo执行了相同的搜索,正如您从扫描对象的数量中可以看到的那样。您还可以看到,所使用的索引是相同的(查看“游标”条目),它们都已经使用了您的my_super_索引

“提示”只告诉Mongo使用它在第一次查询中自动执行的特定索引


第二次搜索很简单,速度更快,因为所有数据可能都已经在缓存中。

我很难找到同样的原因。我发现,当我们有很多索引时,mongo确实比使用提示花费了更多的时间。Mongo基本上花了很多时间来决定使用哪个索引。设想一个场景,其中您有40个索引并执行一个查询。Mongo需要做的第一个任务是哪个索引最适合用于特定的查询。这意味着mongo需要扫描所有键,并且在每次扫描中进行一些计算,以找到一些性能索引(如果使用该键)。提示肯定会加快,因为索引键扫描将被保存

Mongo使用一种算法来确定在未提供任何提示时要使用的索引,然后为接下来的1000次调用缓存用于类似查询的索引

但是,无论何时解释mongo查询,它都将始终运行索引选择算法,因此,与不带提示的explain()相比,带提示的explain()花费的时间总是更少

这里也回答了类似的问题

我将告诉您如何找到速度更快的方法 1) 无索引 它会将每个文档拉入内存以获得结果 2) 带索引 如果该集合有很多索引,它将从缓存中获取索引 3) with.hint(_索引) 它将采用您提到的特定索引

带提示()不带提示() 两次都是。解释(“executionStats”) 使用hint()可以检查值将与检查的值相匹配的值 如果没有提示(),您可以看到TotalKeysInspected值比TotalDocExamined


totalDocsExamined此结果在大多数情况下都会与结果计数完美匹配。

要么索引的速度加快了很多,要么您只是在执行一个缓存查询,它的开销要低得多。我不认为这是因为缓存。如果我在没有提示的情况下运行相同的查询2、3或10次,速度不会快很多,但在有提示的情况下,速度总是会显著加快。您是否可以编辑您的问题以包含find(…)的输出。在没有提示的情况下解释(true)。这将打印可能有助于调试的额外信息。可能需要22毫秒才能确定要使用的索引?@wberry answer在这里是合适的,explain()with hint()将返回rejectedPlans[]为空,因为winningPlan已使用hint()方法提供。对于索引数较高的集合,增量将更为重要<代码>“拒绝的计划”:[{“阶段”:“跳过”,“skipAmount”:493,“inputStage”:{vs
“拒绝的计划”:[]
这是绝对正确的。您的第一个查询运行时间更长,因为它出现页面故障并从磁盘加载了数据。为了对这样的内容进行性能测试,您需要在各种不同的情况下运行数千次,类似于它的生产负载,并对结果进行平均,以便更接近实际情况一个准确的基准。但是,有一点值得注意,数据很可能不在“缓存”中,数据库文件是内存映射的,并且刚刚加载到系统内存中。Mongo通过内存映射文件并让操作系统决定何时交换页面来保持简单,几乎总是根据访问频率和最近程度来决定。听起来很合理。您有任何文档参考资料吗?“此外,$explain操作会重新评估一组候选查询计划,这可能会导致$explain操作的执行方式与普通查询不同。因此,这些操作通常会准确说明MongoDB将如何执行查询,但不会反映这些查询的长度。当您运行explain()时使用hint(),查询优化器不会重新评估查询计划。”摘自简单易懂的答案