首页 > 解决方案 > 为什么当条目已经排序时,mongo 不会用 SORT_MERGE 阶段替换 OR 阶段

问题描述

我有一个包含以下两个索引的集合:{ tags: 1, views: 1 }{ author.username'': 1, views: 1 }

我正在寻找一种以最优化的方式获取以下查询结果的方法

searchArray = ['exam', 'ple', 'dot', 'com']
collection.find({
    $or: [
        { tags: { $all: searchArray } },
        { 'author.username': { $in: searchArray } }
    ]
 }).sort({ views: -1 }).limit(10).explain()
// it takes ~0.05ms with ~150 000 entries

对于先前的请求,查询计划器由于 SORT 阶段而没有给出合适的解决方案。

但是,如果我们单独删除 $ 或每个请求,速度非常快且没有 SORT 阶段。

searchArray = ['exam','ple','dot','com']
collection.find({
  tags: { $all: searchArray }
}).sort({ views: -1 }).limit(10).explain()
// it takes ~0.002ms with ~150 000 entries
searchArray = ['exam','ple','dot','com']
collection.find({
  'author.username': { $in: searchArray }
}).sort({ views: -1 }).limit(10).explain()
// it takes ~0.003ms with ~150 000 entries

所以在单个查询中我们没有 SORT 阶段,这意味着数据已经使用索引进行了排序,那么为什么查询计划器不使用 SORT_MERGE 阶段而不是 OR 阶段呢?

标签: mongodbmongodb-querymongodb-indexes

解决方案


首先,你真的很幸运 aSORT_MERGE正在发生。通常,当您应用使用索引第一部分的 RANGE 查询(您的$inor $all)时,使用索引SORT的第二部分不会发生 a 。因为您正在探索的索引的 B 树的每个分支彼此之间没有排序。这里SORT_MERGE实际上是将 B 树的这些分支合并为一个结果。

在您的情况下,第一个查询的问题是您希望SORT_MERGE彼此之间有两个完全不同的索引。这绝对是不可能的。SORT_MERGE只有当您多次使用相同的索引时才会发生这种情况。

因此,在您的情况下,我建议您仅在该views字段上实际创建索引。至少它应该加快排序。


推荐阅读