为啥 Mongo 提示使查询运行速度提高 10 倍?

Posted

技术标签:

【中文标题】为啥 Mongo 提示使查询运行速度提高 10 倍?【英文标题】:Why does Mongo hint make a query run up to 10 times faster?为什么 Mongo 提示使查询运行速度提高 10 倍? 【发布时间】:2011-12-05 13:07:02 【问题描述】:

如果我使用 explain() 从 shell 运行 mongo 查询,获取使用的索引的名称,然后再次运行相同的查询,但使用 hint() 指定要使用的相同索引 - “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" :  ... 
 

唯一的区别是“毫”字段

有人知道这是为什么吗?

更新:“选择要使用的索引”没有解释它,因为据我所知,mongo 为每个 X(100?)运行选择索引,所以它应该与提示下一个(X -1) 运行

【问题讨论】:

要么索引加快了速度,要么你只是重新执行一个缓存查询,它的开销要低得多。 我不认为这是因为缓存。如果我在没有提示 2、3 或 10 次的情况下运行相同的查询,它不会快得多,但它总是会随着提示显着加快。 您能否编辑您的问题以在没有提示的情况下包含 find(...).explain(true) 的输出。这将打印可能有助于调试的额外信息。 确定使用什么索引可能需要 22 毫秒? @wberry 的答案在这里是合适的,带有 hint() 的 explain() 将返回 deniedPlans[] 为空,因为 winsPlan 已经使用 hint() 方法提供了。对于索引数量较多的集合,Delta 将更为重要。 "rejectedPlans" : [ "stage" : "SKIP", "skipAmount" : 493, "inputStage" : "rejectedPlans" : [] 【参考方案1】:

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

有提示() 没有提示() 两次你都这样做 .explain("executionStats") 使用 hint() 然后您可以检查 totalKeysExamined 值,该值将与 totalDocsExamined 匹配 没有 hint() 你可以看到 totalKeysExamined 值大于 totalDocsExamined

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

【讨论】:

【参考方案2】:

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

但是每当你解释一个 mongo 查询时,它总是会运行索引选择算法,因此与没有提示的 explain() 相比,带有提示的 explain() 总是花费更少的时间。

这里回答了类似的问题 Understanding mongo db explain

【讨论】:

听起来很合理。你有任何文档参考吗? "另外,$explain 操作会重新评估一组候选查询计划,这可能会导致 $explain 操作的执行方式与正常查询不同。因此,这些操作通常提供准确的说明MongoDB 将如何执行查询,但不反映这些查询的长度。当您使用 hint() 运行 explain() 时,查询优化器不会重新评估查询计划。摘自docs.mongodb.org/manual/reference/operator/explain/…【参考方案3】:

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

【讨论】:

简单易懂的答案【参考方案4】:

从扫描对象的数量可以看出,Mongo 两次都进行了相同的搜索。您还可以看到使用的索引是相同的(查看“光标”条目),都已经使用了您的 my_super_index 索引。

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

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

【讨论】:

这完全正确。您的第一个查询运行时间更长,因为它出现页面错误并从磁盘加载数据。为了进行这样的性能测试,您需要在类似于其生产负载的各种不同情况下运行它数千次,并对结果进行平均,以便接近准确的基准。 请注意,数据很可能不在“缓存”中,数据库文件是内存映射的,并且刚刚加载到系统内存中。 Mongo 通过内存映射它的文件并让操作系统决定何时交换页面来保持简单,几乎总是基于访问的频率和新近度。

以上是关于为啥 Mongo 提示使查询运行速度提高 10 倍?的主要内容,如果未能解决你的问题,请参考以下文章

[笔记]为啥hashmap查询速度快? 如何理解hashmap的散列?

s-s-rS - 将报告复制到新文件夹将速度提高 10 倍

TiDB:向量化执行使表达式性能提升10倍成为可能

卧槽!一行代码让 Python 的运行速度提高100倍

一行代码让你的python运行速度提高100倍

一行代码让python的运行速度提高100倍,你信吗?