mongodb 如果不是所有的表达式都被索引,mongo findOne操作中的$或query会使用索引吗?

zwghvu4y  于 2023-01-30  发布在  Go
关注(0)|答案(1)|浏览(126)

Mongo关于$or操作符的文档中写道:
当计算$or表达式中的子句时,MongoDB要么执行集合扫描,要么,如果索引支持所有子句,MongoDB执行索引扫描。也就是说,MongoDB要使用索引来计算$or表达式,$or表达式中的所有子句必须由索引支持。否则,MongoDB将执行集合扫描。
因此,如果希望查询高效,就应该对$or条件中使用的两个属性都建立索引。
但是,我不确定这是否也适用于"findOne"操作,因为我不能使用Mongo的explain功能来执行findOne操作。在我看来,如果只关心返回一个文档,那么首先检查索引条件是合乎逻辑的,因为您可以在找到一个索引条件后退出,而无需关心非索引字段。

示例

让我们在下面假设"email"被索引了,但是username没有。这是一个人为的例子,但是请原谅我。

db.users.findOne(
   {
     $or: [
            { email : 'someUser@gmail.com' },
            { username: 'some-user' }
          ]
   }
)

上面的代码是使用电子邮件索引,还是执行完整的集合扫描,直到找到符合条件的文档?
我找不到任何记录这里会期望什么的东西。有人知道答案吗?

fhity93d

fhity93d1#

好吧,我觉得有点傻--原来我发现的那些说你只能在“find”上运行解释的文档可能只是指你在MongoDB Compass中的时候。
我运行了以下内容(userEmail未编入索引)

this.userModel
        .findOne()
        .where({ $or: [{ _id: id }, { userEmail: email }] })
        .explain();

this.userModel
        .getModelInstance()
        .findOne()
        .where({ _id: id })
        .explain();

...并发现第一个确实执行COLLSCAN,而第二个的计划是IDHACK(基本上它执行正常的ID查找)。
在运行性能测试时,我可以看到在一个包含20 K以上文档的集合中,第一个速度要慢4倍左右(取决于您查找的文档在自然顺序中的位置)

相关问题