草庐IT

mongodb - MongoDB中的 `$or`和 `$in`查询如何排序?

coder 2023-10-29 原文

这是this question的后续内容-有关上下文,请参见。

这个问题涉及链接问题的几个特殊情况-即在使用$in$or运算符时MongoDB中的排序如何工作,以及如何确保使用索引进行排序与​​内存中排序。

$ in:

例如,假设我们有一个集合,其中文档结构为

{a: XXX, b: XXX}

...,并且我们按此顺序在ab上有一个复合索引,并希望运行查询
{a: {$in: [4, 6, 2, 1, 3, 10]}, b: {$gt: 1, $lt: 6}}

如果排序在ab上,将如何进行? $in是排序的相等运算符,但在我看来,即使是这样,也无法对带有索引的b进行排序。我认为,仅当a值数组排在第一位时,才可以使用索引对$in进行排序-但我不知道MongoDB是否这样做。

$ or:

由于$or查询IIUC是作为多个查询处理的,并且大概可以使用它们各自的索引进行排序,因此排序后的结果是否以某种方式合并,或者$or是否对所有结果强制进行内存排序?如果是前者,这个过程的时间复杂度是多少?

最佳答案

注意:该答案基于MongoDB 3.2.4。

值得在MongoDB中发现 explain() 的使用。查询的 explain() 输出(例如db.collection.explain().find(...))使您可以检查查询中使用了哪个索引,并且由于内存中db.collection.explain('executionStats')的限制,使用 SORT 还将显示查询是成功还是失败。

$ in
$in查询可以视为一系列相等查询。例如,{a: {$in: [1,3,5]}}可以被认为是{a:1}, {a:3}, {a:5}。 MongoDB将在继续查询之前对$in数组进行排序,因此{$in: [3,5,1]}{$in: [1,3,5]}没什么不同。

假设集合的索引为

{a:1, b:1}
  • a排序
      db.coll.find({a: {$in: [1,3,5]}}).sort({a:1})
    

    MongoDB将能够使用{a:1,b:1}索引,因为可以将此查询视为{a:1}, {a:3}, {a:5}查询的并集。按{a:1}排序允许使用index prefix,因此MongoDB不需要执行内存中排序。

    同样的情况也适用于查询:
      db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({a:1})
    

    由于sort({a:1})也使用索引前缀(在这种情况下为a),因此不需要内存中的SORT阶段。
  • b排序

    与按a排序相比,这是一个更有趣的情况。例如:
      db.coll.find({a: {$in: [1,3,5]}}).sort({b:1})
    

    此查询的explain()输出将具有一个称为SORT_MERGE的阶段。请记住,查询的find()部分可以被视为{a:1}, {a:3}, {a:5}

    由于db.coll.find({a:1}).sort({b:1})索引的性质,查询SORT不需要具有内存中的{a:1,b:1}阶段:也就是说,在满足b的相等性参数之后,MongoDB可以简单地遍历(排序的)索引并返回按a排序的文档。例如,对于每个a,由于索引,已经有许多b已按b排序。

    使用$in,整个查询可以认为是:
  • db.coll.find({a:1}).sort({b:1})
  • db.coll.find({a:3}).sort({b:1})
  • db.coll.find({a:5}).sort({b:1})
  • 获取上面的单个查询结果,并使用b的值执行合并。该查询不需要在内存中进行排序,因为各个查询结果已经通过b进行了排序。 MongoDB只需要将(已排序的)子查询结果合并为一个结果。

  • 同样,查询
      db.coll.find({a: {$in: [1,3,5]} ,b:{$gte:1, $lt:2}}).sort({b:1})
    

    还使用了SORT_MERGE阶段,与上面的查询非常相似。不同之处在于,每个查询基于每个b(根据索引b进行排序,按a排序)的b范围(而不是每个{a:1,b:1})查询输出文档。因此,查询不需要在内存中进行排序。
    $或

    为了使$or查询使用索引every clause in the $or expression must have an index associated with it。如果满足此要求,则查询可以像SORT_MERGE查询一样使用$in阶段。例如:
    db.coll.explain().find({$or:[{a:1},{a:3},{a:5}]}).sort({b:1})
    

    与上面的SORT_MERGE示例中的查询计划,索引使用和$in阶段几乎相同。本质上,查询可以认为是:
  • db.coll.find({a:1}).sort({b:1})
  • db.coll.find({a:3}).sort({b:1})
  • db.coll.find({a:5}).sort({b:1})
  • 获取上面的单个查询结果,并使用b的值执行合并。

  • 就像前面的$in示例一样。

    但是,此查询:
    db.coll.explain().find({$or:[{a:1},{b:1}]}).sort({b:1})
    

    不能使用任何索引(因为我们没有{b:1}索引)。该查询将导致集合扫描,并且由于没有使用索引,因此将具有内存中排序阶段。

    但是,如果我们创建索引{b:1},则查询将像下面这样进行:
  • db.coll.find({a:1}).sort({b:1})
  • db.coll.find({b:1}).sort({b:1})
  • 接受上面的单个查询结果,并使用b的值执行合并(由于索引{a:1,b:1}{b:1},该值已经在两个子查询中进行了排序)。

  • MongoDB将合并{a:1}{b:1}查询的结果,并对结果进行合并。合并过程是线性时间,例如O(n)

    总之,在$or查询中,每个词都必须有一个索引,包括sort()阶段。否则,MongoDB将必须执行内存中排序。

    关于mongodb - MongoDB中的 `$or`和 `$in`查询如何排序?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36490738/

    有关mongodb - MongoDB中的 `$or`和 `$in`查询如何排序?的更多相关文章

    1. ruby - 如何使用 Nokogiri 的 xpath 和 at_xpath 方法 - 2

      我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div

    2. ruby - 如何从 ruby​​ 中的字符串运行任意对象方法? - 2

      总的来说,我对ruby​​还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用

    3. ruby - 其他文件中的 Rake 任务 - 2

      我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时

    4. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

      作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

    5. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

      关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

    6. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

      我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

    7. ruby-on-rails - Rails 3 中的多个路由文件 - 2

      Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题

    8. ruby-on-rails - 如何验证 update_all 是否实际在 Rails 中更新 - 2

      给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru

    9. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

      我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

    10. ruby - ECONNRESET (Whois::ConnectionError) - 尝试在 Ruby 中查询 Whois 时出错 - 2

      我正在用Ruby编写一个简单的程序来检查域列表是否被占用。基本上它循环遍历列表,并使用以下函数进行检查。require'rubygems'require'whois'defcheck_domain(domain)c=Whois::Client.newc.query("google.com").available?end程序不断出错(即使我在google.com中进行硬编码),并打印以下消息。鉴于该程序非常简单,我已经没有什么想法了-有什么建议吗?/Library/Ruby/Gems/1.8/gems/whois-2.0.2/lib/whois/server/adapters/base.

    随机推荐