问题 MongoDB索引和$或运算符


对不起,如果之前有人询问过。我找不到明确的答案。如果我的查询包含$或运算符,我可以在mongodb索引上查询吗?我的查询看起来像这样:

    // find everything in the collection
    $cursor = $collection->find(array(
   '$or' => array( 
        array('album_id' => array(
            '$in' => $this->my_album_ids
            ),
        'type' => array(
            '$in' => array('like','comment')
            )
         ),
       array(
    'user_id' => (int)session_item('user_id'),
        'type' => 'message',
        'reply' => 'no'
         )
       ),
        'timestamp' => array('$gt' => (int)$since)))->sort(array('timestamp'=>-1))->skip($start)->limit($amount);  

示例是在PHP中,但我想这适用于任何语言。

更新:

以下是我的索引,但上面的查询不使用它们。虽然看起来对我不对。

    $collection->ensureIndex(array(
        'album_id' => 1,
        'type' => 1,
        'timestamp' => -1,
    ));

    $collection->ensureIndex(array(
        'user_id' => 1,
        'type' => 1,
        'reply' => 1,
        'timestamp' => -1,
    ));

这是我的解释()

Array
(
    [cursor] => BasicCursor
    [nscanned] => 12
    [nscannedObjects] => 12
    [n] => 6
    [scanAndOrder] => 1
    [millis] => 0
    [nYields] => 0
    [nChunkSkips] => 0
    [isMultiKey] => 
    [indexOnly] => 
    [indexBounds] => Array
        (
        )

    [allPlans] => Array
        (
            [0] => Array
                (
                    [cursor] => BasicCursor
                    [indexBounds] => Array
                        (
                        )

                )

        )

    [oldPlan] => Array
        (
            [cursor] => BasicCursor
            [indexBounds] => Array
                (
                )

        )

)

9145
2017-07-29 11:55


起源



答案:


是的,$或查询将根据需要使用索引。例如 :

> db.test.ensureIndex({a:1})
> db.test.ensureIndex({b:1})
> db.test.find({$or:[{a:1}, {b:2}]}).explain()
{
        "clauses" : [
                {
                        "cursor" : "BtreeCursor a_1",
                        "nscanned" : 0,
                        "nscannedObjects" : 0,
                        "n" : 0,
                        "millis" : 0,
                        "nYields" : 0,
                        "nChunkSkips" : 0,
                        "isMultiKey" : false,
                        "indexOnly" : false,
                        "indexBounds" : {
                                "a" : [
                                        [
                                                1,
                                                1
                                        ]
                                ]
                        }
                },
                {
                        "cursor" : "BtreeCursor b_1",
                        "nscanned" : 0,
                        "nscannedObjects" : 0,
                        "n" : 0,
                        "millis" : 1,
                        "nYields" : 0,
                        "nChunkSkips" : 0,
                        "isMultiKey" : false,
                        "indexOnly" : false,
                        "indexBounds" : {
                                "b" : [
                                        [
                                                2,
                                                2
                                        ]
                                ]
                        }
                }
        ],
        "nscanned" : 0,
        "nscannedObjects" : 0,
        "n" : 0,
        "millis" : 1
}

7
2017-07-29 15:44



很酷,很高兴知道这是可能的。但是我的查询和索引似乎仍然互相忽略。我已经更新了关于如何创建索引的帖子。难道我做错了什么?谢谢。 - noel
很可能你的一个内部或子句不符合指定的索引。您是否对单独的部分进行了解释()并查看是否使用了正确的索引?以shell语法而不是特定语言发布问题是有帮助的。没有比我愿意投入更多努力,我无法阅读上述大部分内容;) - Remon van Vliet
如果我是你,我会在没有OR子句的情况下慢慢构建查询的每个部分。向您自己证明复合索引中的顺序是正确的。然后继续构建您需要的最终查询。我相信你的问题很快就会得到解决。 - Jon Kern


答案:


是的,$或查询将根据需要使用索引。例如 :

> db.test.ensureIndex({a:1})
> db.test.ensureIndex({b:1})
> db.test.find({$or:[{a:1}, {b:2}]}).explain()
{
        "clauses" : [
                {
                        "cursor" : "BtreeCursor a_1",
                        "nscanned" : 0,
                        "nscannedObjects" : 0,
                        "n" : 0,
                        "millis" : 0,
                        "nYields" : 0,
                        "nChunkSkips" : 0,
                        "isMultiKey" : false,
                        "indexOnly" : false,
                        "indexBounds" : {
                                "a" : [
                                        [
                                                1,
                                                1
                                        ]
                                ]
                        }
                },
                {
                        "cursor" : "BtreeCursor b_1",
                        "nscanned" : 0,
                        "nscannedObjects" : 0,
                        "n" : 0,
                        "millis" : 1,
                        "nYields" : 0,
                        "nChunkSkips" : 0,
                        "isMultiKey" : false,
                        "indexOnly" : false,
                        "indexBounds" : {
                                "b" : [
                                        [
                                                2,
                                                2
                                        ]
                                ]
                        }
                }
        ],
        "nscanned" : 0,
        "nscannedObjects" : 0,
        "n" : 0,
        "millis" : 1
}

7
2017-07-29 15:44



很酷,很高兴知道这是可能的。但是我的查询和索引似乎仍然互相忽略。我已经更新了关于如何创建索引的帖子。难道我做错了什么?谢谢。 - noel
很可能你的一个内部或子句不符合指定的索引。您是否对单独的部分进行了解释()并查看是否使用了正确的索引?以shell语法而不是特定语言发布问题是有帮助的。没有比我愿意投入更多努力,我无法阅读上述大部分内容;) - Remon van Vliet
如果我是你,我会在没有OR子句的情况下慢慢构建查询的每个部分。向您自己证明复合索引中的顺序是正确的。然后继续构建您需要的最终查询。我相信你的问题很快就会得到解决。 - Jon Kern


Mongo在排序的OR查询中不使用IndexBounds。 尝试

db.test.find({$or:[{a:1}, {b:2}]}).sort(somesort).explain();

和IndexBounds一起使用 $minElement 和 $maxElement


4
2017-10-03 11:03