mongo查询如何包含“或”使用索引

时间:2017-06-27 07:47:53

标签: mongodb indexing

这是一个关于如何在查询具有“或”时创建高效索引的问题。没有“或”,我知道如何创建有效的索引。

这是我的疑问。

db.collection.find({
    'msg.sendTime':{$gt:1},
    'msg.msgType':{$in:["chat","g_card"]},
     $or:[{'msg.recvId':{$in:['xm80049258']}},{'msg.userId':'xm80049258'}],
     $orderby:{'msg.sendTime':-1}})

阅读完一篇文章后,我在msg.recvId和msg.userId上创建了两个单一的索引,这很有意义。

  1. 我想知道mongodb何时执行“或”,它是否首先分割所有文件,然后使用msg.sendTime和msg.msgType?

  2. 如何在这种情况下创建高效索引?我应该创建索引(msg.sendTime:1,msg.msgType:1,msg.recvId:1)和 (msg.sendTime:1,msg.msgType:1,msg.userId:1)

  3. 非常感谢。

1 个答案:

答案 0 :(得分:0)

$or Clauses and Indexes释义:

  

在评估$或表达式中的子句时,MongoDB执行集合扫描,或者如果索引支持所有子句,MongoDB将执行索引扫描。也就是说,对于MongoDB使用索引来计算$或表达式,$或表达式中的所有子句必须由索引支持。

同样来自Indexing Strategies

  

通常,MongoDB只使用一个索引来完成大多数查询。但是,$或查询的每个子句都可以使用不同的索引

这些段落对$or查询的意思是:

  • find()查询中,只能使用一个索引。因此,最好创建一个与查询中的字段对齐的索引。否则,MongoDB将进行集合扫描。
  • 除了查询是$or查询之外,MongoDB可以使用$or个字词的
  • 结合使用,如果您的查询中包含$or,最好将$or字词作为顶级字词,并为每个字词创建一个索引分别

所以回答你的问题:

  

我想知道mongodb何时执行"或",它是否首先划分所有文档,然后使用msg.sendTime和msg.msgType?

如果您的查询具有顶级$or子句,MongoDB可以使用每个子句一个索引。否则,它将执行集合扫描或半集合扫描。例如,如果您有索引:

db.collection.createIndex({a: 1, b: 1})

您可以创建两种常规类型的查询:

1。 $or不在查询的顶层

此查询可以使用索引,但不具备性能:

db.collection.find({a: 1, $or: [{b: 1}, {b: 2}]})

因为查询的explain()输出是:

> db.collection.explain().find({a: 1, $or: [{b: 1}, {b: 2}]})
{
"queryPlanner": {
...
        "indexBounds": {
        "a": [
            "[1.0, 1.0]"
        ],
        "b": [
            "[MinKey, MaxKey]"
        ]
...

请注意,查询计划程序无法使用b字段的正确边界,因为它正在进行半集合扫描(因为它正在从{{1}搜索bMinKey,即一切)。上面的查询规划器结果基本上是说:"查找MaxKey的文档,并扫描a = 1的所有文件,其值为b1 "

2。查询顶层的2

但是,将$or子句拉到顶层:

$or

将导致此查询计划:

db.collection.find({$or: [{a: 1, b: 1}, {a: 1, b: 2}]})

请注意,> db.test.explain().find({$or: [{a: 1, b: 1}, {a: 1, b: 2}]}) { "queryPlanner": { ... "winningPlan": { "stage": "SUBPLAN", ... "inputStages": [ { "stage": "IXSCAN", ... "indexBounds": { "a": [ "[1.0, 1.0]" ], "b": [ "[1.0, 1.0]" ] } }, { "stage": "IXSCAN", ... "indexBounds": { "a": [ "[1.0, 1.0]" ], "b": [ "[2.0, 2.0]" ] 的每个术语都被视为一个单独的查询,每个查询都有一个紧密的边界。因此,上面的查询计划是:"查找$ora = 1, b = 1" 的文档。可以想象,与先前的查询相比,此查询将更加高效。

关于你的第二个问题:

  

在这种情况下如何创建高效索引?我应该创建索引(msg.sendTime:1,msg.msgType:1,msg.recvId:1)和(msg.sendTime:1,msg.msgType:1,msg.userId:1)

如上所述,您需要将正确的查询与适当的索引相结合,以获得最佳结果。您建议的两个索引将能够被MongoDB使用,并且如果您重新排列查询以在查询的顶级中包含a = 1, b = 2,那么这些索引将最有效。

我建议您了解MongoDB的$or输出,因为它是确定您的查询是否使用正确索引的最佳工具。

您可能会发现有用的相关资源是: