为啥 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 倍?的主要内容,如果未能解决你的问题,请参考以下文章