MongoDB(和Mongoose.js):查询条件的顺序是否重要?

14

在创建一个简单的MongoDB查询时,我对查询中的条件顺序有疑问 - 比如(使用Mongoose.js语法):

conditions = { archived: false, first_name: "Billy" };

对比

conditions = { first_name: "Billy", archived: false };

..在一个简单的find()函数中:

User.find(conditions, function(err, users) { <some logic> });

假设使用简单的单键索引策略:

UserSchema.index( { first_name: 1, archived: 1} );

..上面列出的条件顺序是否重要?

重要提示:我知道对于复合索引,顺序很重要,但是针对单键索引查询,如上所述,我想知道是否重要。同时也对完全没有索引的查询感兴趣。 :)

另一种解释:换句话说,假设有100个User(50个已存档,50个未存档),给定两种可能的MongoDB内部搜索策略:

  1. 首先过滤掉所有50个archived用户,然后在剩余的50个非存档用户中搜索名称为“Billy”的first_name值。
  2. 首先搜索所有100个User文档,查找first_name值为“Billy”的文档,然后通过删除任何已归档的Billy来过滤找到的对象。

..我会认为#1更快(在具有两个以上条件的大型查询中潜在地快得多)。 但无论哪一个更快以及为什么,肯定有一个更快。

CORE QUESTION: 在复合索引的广阔而强大的世界之外,MongoDB是否知道如何自动执行其最有效/快速的搜索/过滤,而不管字段和顺序如何? 或者我们需要通过编程方式告诉系统什么是最好的(通过呈现条件的顺序等)?

1个回答

20

我对你的问题有点困惑,因为你提供的索引 ({ first_name: 1, archived: 1 }) 一个复合索引。以下所有查询都将使用该复合索引:

conditions = { archived: false, first_name: "Billy" };
conditions = { first_name: "Billy", archived: false };
conditions = { first_name: "Billy" };
现在,假设我们有两个独立的索引,{ first_name: 1 }和{ archived: 1 }。在这种情况下,MongoDB会进行查询优化来确定使用哪个索引最有效。您可以在此处阅读有关MongoDB执行的查询优化的更多信息。 因此,MongoDB查询优化器很可能会对您提供的两个多条件查询使用相同的索引:
conditions = { archived: false, first_name: "Billy" };
conditions = { first_name: "Billy", archived: false };

或者,您可以使用hint来强制MongoDB使用您选择的索引。一般而言,这可能不是一个好主意。您还可以手动检查哪个索引对于特定查询最有效,详见此处

您可以在Mongo shell中使用.explain()功能来查看查询正在使用哪个索引。(如果没有使用索引,则在结果文档中将看到"cursor" : "BasicCursor"。另一方面,如果正在使用复合索引,则会看到类似于"cursor" : "BtreeCursor first_name_1_archived_1"的内容。如果使用了其中一个单字段索引,您可能会看到"cursor" : "BtreeCursor archived_1"。)

此外,MongoDB的搜索策略如下:

  • 首先,遍历索引,使用索引边界来过滤尽可能多的文档;
  • 接下来,如果有其他不能使用索引满足的谓词,
    • 获取文档,
    • 应用谓词,
    • 并适当地将文档包含/排除在结果中。

查询优化器并行运行所有可能的查询计划,并选择“最佳”计划,但所有查询计划都遵循上述策略。(BasicCursor是一个退化情况:它遍历所有文档并对每个文档应用谓词。)

简而言之? Matcher足够智能,可以匹配任何顺序呈现的相等谓词。

这有意义吗?


1
谢谢@Amalia - 具有讽刺意味的是,昨晚我参加了一个MongoDB聚会,并获得了很多相同的信息。太棒了,我登录后你已经比我回答得更好了。 :) - toblerpwn
好问题,好答案! - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接